mirror of https://github.com/mongodb/mongo
390 lines
16 KiB
JavaScript
390 lines
16 KiB
JavaScript
/**
|
|
* Tests behavior of BinData $convert.
|
|
* @tags: [
|
|
* requires_fcv_83,
|
|
* ]
|
|
*/
|
|
|
|
import {runConvertTests} from "jstests/libs/query/convert_shared.js";
|
|
|
|
const coll = db.expression_convert_with_base;
|
|
coll.drop();
|
|
|
|
const requiresFCV83 = true;
|
|
|
|
const conversionTestDocs = [
|
|
// Convert number to string.
|
|
{_id: 1, input: NumberInt(10), target: "string", base: 2, expected: "1010"},
|
|
{_id: 2, input: 10.0, target: "string", base: 2, expected: "1010"},
|
|
{_id: 3, input: 10, target: "string", base: 2, expected: "1010"},
|
|
{_id: 4, input: NumberLong(10), target: "string", base: 2, expected: "1010"},
|
|
{_id: 5, input: NumberDecimal(10.0), target: "string", base: 2, expected: "1010"},
|
|
|
|
{_id: 6, input: NumberInt(10), target: "string", base: 8, expected: "12"},
|
|
{_id: 7, input: 10.0, target: "string", base: 8, expected: "12"},
|
|
{_id: 8, input: 10, target: "string", base: 8, expected: "12"},
|
|
{_id: 9, input: NumberLong(10), target: "string", base: 8, expected: "12"},
|
|
{_id: 10, input: NumberDecimal(10.0), target: "string", base: 8, expected: "12"},
|
|
|
|
{_id: 11, input: NumberInt(10), target: "string", base: 10, expected: "10"},
|
|
{_id: 12, input: 10.0, target: "string", base: 10, expected: "10"},
|
|
{_id: 13, input: 10, target: "string", base: 10, expected: "10"},
|
|
{_id: 14, input: NumberLong(10), target: "string", base: 10, expected: "10"},
|
|
{_id: 15, input: NumberDecimal(10.0), target: "string", base: 10, expected: "10"},
|
|
|
|
{_id: 16, input: NumberInt(10), target: "string", base: 16, expected: "A"},
|
|
{_id: 17, input: 10.0, target: "string", base: 16, expected: "A"},
|
|
{_id: 18, input: 10, target: "string", base: 16, expected: "A"},
|
|
{_id: 19, input: NumberLong(10), target: "string", base: 16, expected: "A"},
|
|
{_id: 20, input: NumberDecimal(10.0), target: "string", base: 16, expected: "A"},
|
|
|
|
// Convert number to string with negative input.
|
|
{_id: 21, input: NumberInt(-10), target: "string", base: 2, expected: "-1010"},
|
|
{_id: 22, input: -10, target: "string", base: 8, expected: "-12"},
|
|
{_id: 23, input: NumberLong(-10), target: "string", base: 10, expected: "-10"},
|
|
{_id: 24, input: NumberDecimal("-10"), target: "string", base: 16, expected: "-A"},
|
|
|
|
// Convert string to number.
|
|
{_id: 25, input: "1010", target: "int", base: 2, expected: NumberInt(10)},
|
|
{_id: 26, input: "1010", target: "double", base: 2, expected: 10.0},
|
|
{_id: 27, input: "1010", target: "long", base: 2, expected: NumberLong(10)},
|
|
{_id: 28, input: "1010", target: "decimal", base: 2, expected: NumberDecimal("10")},
|
|
|
|
{_id: 29, input: "12", target: "int", base: 8, expected: NumberInt(10)},
|
|
{_id: 30, input: "12", target: "double", base: 8, expected: 10.0},
|
|
{_id: 31, input: "12", target: "long", base: 8, expected: NumberLong(10)},
|
|
{_id: 32, input: "12", target: "decimal", base: 8, expected: NumberDecimal("10")},
|
|
|
|
{_id: 33, input: "10", target: "int", base: 10, expected: NumberInt(10)},
|
|
{_id: 34, input: "10", target: "double", base: 10, expected: 10.0},
|
|
{_id: 35, input: "10", target: "long", base: 10, expected: NumberLong(10)},
|
|
{_id: 36, input: "10", target: "decimal", base: 10, expected: NumberDecimal("10")},
|
|
|
|
{_id: 37, input: "A", target: "int", base: 16, expected: NumberInt(10)},
|
|
{_id: 38, input: "A", target: "double", base: 16, expected: 10.0},
|
|
{_id: 39, input: "A", target: "long", base: 16, expected: NumberLong(10)},
|
|
{_id: 40, input: "A", target: "decimal", base: 16, expected: NumberDecimal("10")},
|
|
{_id: 41, input: "a", target: "int", base: 16, expected: NumberInt(10)},
|
|
{_id: 42, input: "a", target: "double", base: 16, expected: 10.0},
|
|
{_id: 43, input: "a", target: "long", base: 16, expected: NumberLong(10)},
|
|
{_id: 44, input: "a", target: "decimal", base: 16, expected: NumberDecimal("10")},
|
|
|
|
// Convert string to number with negative input.
|
|
{_id: 45, input: "-1010", target: "int", base: 2, expected: NumberInt(-10)},
|
|
{_id: 46, input: "-12", target: "double", base: 8, expected: -10.0},
|
|
{_id: 47, input: "-10", target: "long", base: 10, expected: NumberLong(-10)},
|
|
{_id: 48, input: "-A", target: "decimal", base: 16, expected: NumberDecimal("-10")},
|
|
|
|
// Base param is validated but ignored when conversion is not between string and number.
|
|
{_id: 49, input: 1.9, target: "double", base: 2, expected: 1.9},
|
|
{_id: 50, input: 1.9, target: "date", base: 2, expected: ISODate("1970-01-01T00:00:00.001Z")},
|
|
{_id: 51, input: "str", target: "string", base: 2, expected: "str"},
|
|
{
|
|
_id: 52,
|
|
input: "0123456789abcdef01234567",
|
|
target: "objectId",
|
|
base: 2,
|
|
expected: ObjectId("0123456789abcdef01234567"),
|
|
},
|
|
{_id: 53, input: ObjectId("0123456789abcdef01234567"), target: "bool", expected: true},
|
|
{
|
|
_id: 54,
|
|
input: ObjectId("0123456789abcdef01234567"),
|
|
target: "objectId",
|
|
base: 2,
|
|
expected: ObjectId("0123456789abcdef01234567"),
|
|
},
|
|
{_id: 55, input: false, target: "double", base: 2, expected: 0.0},
|
|
{_id: 56, input: false, target: "bool", base: 2, expected: false},
|
|
{
|
|
_id: 57,
|
|
input: ISODate("1970-01-01T00:00:00.123Z"),
|
|
target: "date",
|
|
base: 2,
|
|
expected: ISODate("1970-01-01T00:00:00.123Z"),
|
|
},
|
|
{
|
|
_id: 58,
|
|
input: ISODate("1970-01-01T00:00:00.123Z"),
|
|
target: "long",
|
|
base: 2,
|
|
expected: NumberLong(123),
|
|
},
|
|
{_id: 59, input: NumberInt(1), target: "int", base: 2, expected: NumberInt(1)},
|
|
{_id: 60, input: NumberInt(1), target: "long", base: 2, expected: NumberLong(1)},
|
|
{_id: 61, input: NumberLong(1), target: "double", base: 2, expected: 1.0},
|
|
{_id: 62, input: NumberLong(1), target: "long", base: 2, expected: NumberLong(1)},
|
|
{_id: 63, input: NumberDecimal("1.9"), target: "double", base: 2, expected: 1.9},
|
|
{_id: 64, input: NumberDecimal("1.9"), target: "bool", base: 2, expected: true},
|
|
{
|
|
_id: 65,
|
|
input: NumberDecimal("1.9"),
|
|
target: "decimal",
|
|
base: 2,
|
|
expected: NumberDecimal("1.9"),
|
|
},
|
|
|
|
// Complementary examples of illegal conversions.
|
|
{_id: 66, input: "A", target: "int", base: 16, expected: NumberInt(10)},
|
|
|
|
{_id: 67, input: "8", target: "double", base: 10, expected: 8.0},
|
|
{_id: 68, input: "8", target: "long", base: 16, expected: NumberLong(8)},
|
|
|
|
{_id: 69, input: "2", target: "decimal", base: 8, expected: NumberDecimal("2")},
|
|
{_id: 70, input: "2", target: "int", base: 10, expected: NumberInt(2)},
|
|
{_id: 71, input: "2", target: "double", base: 16, expected: 2},
|
|
|
|
// Base null equals empty base.
|
|
{_id: 72, input: NumberInt(10), target: "string", base: null, expected: "10"},
|
|
{_id: 73, input: 10, target: "string", base: null, expected: "10"},
|
|
{_id: 74, input: NumberLong(10), target: "string", base: null, expected: "10"},
|
|
{_id: 75, input: NumberDecimal("10"), target: "string", base: null, expected: "10"},
|
|
|
|
{_id: 76, input: "10", target: "int", base: null, expected: NumberInt(10)},
|
|
{_id: 77, input: "10", target: "double", base: null, expected: 10.0},
|
|
{_id: 78, input: "10", target: "long", base: null, expected: NumberLong(10)},
|
|
{_id: 79, input: "10", target: "decimal", base: null, expected: NumberDecimal("10")},
|
|
|
|
// Conversion from number to string with large numbers.
|
|
{
|
|
_id: 80,
|
|
input: NumberInt(2147483647),
|
|
target: "string",
|
|
base: 2,
|
|
expected: "1111111111111111111111111111111",
|
|
},
|
|
{
|
|
_id: 81,
|
|
input: NumberInt(-2147483648),
|
|
target: "string",
|
|
base: 2,
|
|
expected: "-10000000000000000000000000000000",
|
|
},
|
|
{
|
|
_id: 82,
|
|
input: NumberLong("9223372036854775807"),
|
|
target: "string",
|
|
base: 2,
|
|
expected: "111111111111111111111111111111111111111111111111111111111111111",
|
|
},
|
|
{
|
|
_id: 83,
|
|
input: NumberLong("-9223372036854775808"),
|
|
target: "string",
|
|
base: 2,
|
|
expected: "-1000000000000000000000000000000000000000000000000000000000000000",
|
|
},
|
|
|
|
{_id: 84, input: NumberInt(2147483647), target: "string", base: 8, expected: "17777777777"},
|
|
{_id: 85, input: NumberInt(-2147483648), target: "string", base: 8, expected: "-20000000000"},
|
|
{
|
|
_id: 86,
|
|
input: NumberLong("9223372036854775807"),
|
|
target: "string",
|
|
base: 8,
|
|
expected: "777777777777777777777",
|
|
},
|
|
{
|
|
_id: 87,
|
|
input: NumberLong("-9223372036854775808"),
|
|
target: "string",
|
|
base: 8,
|
|
expected: "-1000000000000000000000",
|
|
},
|
|
|
|
{_id: 88, input: NumberInt(2147483647), target: "string", base: 10, expected: "2147483647"},
|
|
{_id: 89, input: NumberInt(-2147483648), target: "string", base: 10, expected: "-2147483648"},
|
|
{
|
|
_id: 90,
|
|
input: NumberLong("9223372036854775807"),
|
|
target: "string",
|
|
base: 10,
|
|
expected: "9223372036854775807",
|
|
},
|
|
{
|
|
_id: 91,
|
|
input: NumberLong("-9223372036854775808"),
|
|
target: "string",
|
|
base: 10,
|
|
expected: "-9223372036854775808",
|
|
},
|
|
|
|
{_id: 92, input: NumberInt(2147483647), target: "string", base: 16, expected: "7FFFFFFF"},
|
|
{_id: 93, input: NumberInt(-2147483648), target: "string", base: 16, expected: "-80000000"},
|
|
{
|
|
_id: 94,
|
|
input: NumberLong("9223372036854775807"),
|
|
target: "string",
|
|
base: 16,
|
|
expected: "7FFFFFFFFFFFFFFF",
|
|
},
|
|
{
|
|
_id: 95,
|
|
input: NumberLong("-9223372036854775808"),
|
|
target: "string",
|
|
base: 16,
|
|
expected: "-8000000000000000",
|
|
},
|
|
];
|
|
|
|
//
|
|
// Unsupported conversions.
|
|
//
|
|
const illegalConversionTestDocs = [
|
|
// Given string is not valid in the base.
|
|
{_id: 1, input: "zzz", target: "int", base: 2},
|
|
{_id: 2, input: "zzz", target: "double", base: 8},
|
|
{_id: 3, input: "zzz", target: "long", base: 10},
|
|
{_id: 4, input: "zzz", target: "decimal", base: 16},
|
|
|
|
{_id: 5, input: "A", target: "int", base: 2},
|
|
{_id: 6, input: "A", target: "double", base: 8},
|
|
{_id: 7, input: "A", target: "long", base: 10},
|
|
|
|
{_id: 8, input: "8", target: "decimal", base: 2},
|
|
{_id: 9, input: "8", target: "int", base: 8},
|
|
|
|
{_id: 10, input: "2", target: "double", base: 2},
|
|
|
|
// Trying the convert a non-integral number using base.
|
|
{_id: 11, input: 10.1, target: "string", base: 2},
|
|
{_id: 12, input: NumberDecimal(10.1), target: "string", base: 8},
|
|
{_id: 13, input: 10.1, target: "string", base: 10},
|
|
{_id: 14, input: NumberDecimal(10.1), target: "string", base: 16},
|
|
|
|
// Number represented by given string is too large to fit in number.
|
|
{_id: 15, input: "10000000000000000000000000000000", target: "int", base: 2},
|
|
{
|
|
_id: 16,
|
|
input: "1000000000000000000000000000000000000000000000000000000000000000",
|
|
target: "double",
|
|
base: 2,
|
|
},
|
|
{
|
|
_id: 17,
|
|
input: "1000000000000000000000000000000000000000000000000000000000000000",
|
|
target: "long",
|
|
base: 2,
|
|
},
|
|
{
|
|
_id: 18,
|
|
input: "1000000000000000000000000000000000000000000000000000000000000000",
|
|
target: "decimal",
|
|
base: 2,
|
|
},
|
|
{_id: 19, input: "-10000000000000000000000000000001", target: "int", base: 2},
|
|
{
|
|
_id: 20,
|
|
input: "-1000000000000000000000000000000000000000000000000000000000000001",
|
|
target: "double",
|
|
base: 2,
|
|
},
|
|
{
|
|
_id: 21,
|
|
input: "-1000000000000000000000000000000000000000000000000000000000000001",
|
|
target: "long",
|
|
base: 2,
|
|
},
|
|
{
|
|
_id: 22,
|
|
input: "-1000000000000000000000000000000000000000000000000000000000000001",
|
|
target: "decimal",
|
|
base: 2,
|
|
},
|
|
|
|
{_id: 23, input: "20000000000", target: "int", base: 8},
|
|
{_id: 24, input: "1000000000000000000000", target: "double", base: 8},
|
|
{_id: 25, input: "1000000000000000000000", target: "long", base: 8},
|
|
{_id: 26, input: "1000000000000000000000", target: "decimal", base: 8},
|
|
{_id: 27, input: "-20000000001", target: "int", base: 8},
|
|
{_id: 28, input: "-1000000000000000000001", target: "double", base: 8},
|
|
{_id: 29, input: "-1000000000000000000001", target: "long", base: 8},
|
|
{_id: 30, input: "-1000000000000000000001", target: "decimal", base: 8},
|
|
|
|
{_id: 31, input: "2147483648", target: "int", base: 10},
|
|
{_id: 32, input: "9223372036854775808", target: "double", base: 10},
|
|
{_id: 33, input: "9223372036854775808", target: "long", base: 10},
|
|
{_id: 34, input: "9223372036854775808", target: "decimal", base: 10},
|
|
{_id: 35, input: "-2147483649", target: "int", base: 10},
|
|
{_id: 36, input: "-9223372036854775809", target: "double", base: 10},
|
|
{_id: 37, input: "-9223372036854775809", target: "long", base: 10},
|
|
{_id: 38, input: "-9223372036854775809", target: "decimal", base: 10},
|
|
|
|
{_id: 39, input: "80000000", target: "int", base: 16},
|
|
{_id: 40, input: "8000000000000000", target: "double", base: 16},
|
|
{_id: 41, input: "8000000000000000", target: "long", base: 16},
|
|
{_id: 42, input: "8000000000000000", target: "decimal", base: 16},
|
|
{_id: 43, input: "-80000001", target: "int", base: 16},
|
|
{_id: 44, input: "-8000000000000001", target: "double", base: 16},
|
|
{_id: 45, input: "-8000000000000001", target: "long", base: 16},
|
|
{_id: 46, input: "-8000000000000001", target: "decimal", base: 16},
|
|
|
|
// Reject conversions with base prefix
|
|
{_id: 47, input: "0b1010", target: "int", base: 2},
|
|
{_id: 48, input: "0B1010", target: "double", base: 2},
|
|
{_id: 49, input: "0o12", target: "long", base: 8},
|
|
{_id: 50, input: "0O12", target: "decimal", base: 8},
|
|
{_id: 53, input: "0xa", target: "long", base: 16},
|
|
{_id: 54, input: "0XA", target: "decimal", base: 16},
|
|
];
|
|
|
|
//
|
|
// Conversions with invalid 'base' argument.
|
|
//
|
|
const invalidArgumentValueDocs = [
|
|
// Base must be integral.
|
|
{_id: 1, input: NumberInt(10), target: "string", base: 2.1, expectedCode: 3501300},
|
|
{_id: 2, input: 10, target: "string", base: 2.1, expectedCode: 3501300},
|
|
{_id: 3, input: NumberLong(10), target: "string", base: 2.1, expectedCode: 3501300},
|
|
{_id: 4, input: NumberDecimal(10.0), target: "string", base: 2.1, expectedCode: 3501300},
|
|
|
|
{_id: 5, input: "1010", target: "int", base: 2.1, expectedCode: 3501300},
|
|
{_id: 6, input: "1010", target: "double", base: 2.1, expectedCode: 3501300},
|
|
{_id: 7, input: "1010", target: "long", base: 2.1, expectedCode: 3501300},
|
|
{_id: 8, input: "1010", target: "decimal", base: 2.1, expectedCode: 3501300},
|
|
|
|
// Base must be 2, 8, 10 or 16
|
|
{_id: 9, input: NumberInt(10), target: "string", base: 3, expectedCode: 3501301},
|
|
{_id: 10, input: 10, target: "string", base: "invalid", expectedCode: 3501300},
|
|
{_id: 11, input: NumberLong(10), target: "string", base: 0, expectedCode: 3501301},
|
|
{_id: 12, input: NumberDecimal(10.0), target: "string", base: 12, expectedCode: 3501301},
|
|
|
|
{_id: 13, input: "1010", target: "int", base: 3, expectedCode: 3501301},
|
|
{_id: 14, input: "1010", target: "double", base: "invalid", expectedCode: 3501300},
|
|
{_id: 15, input: "1010", target: "long", base: 0, expectedCode: 3501301},
|
|
{_id: 16, input: "1010", target: "decimal", base: 12, expectedCode: 3501301},
|
|
|
|
// Base is validated, even when it's not used.
|
|
{_id: 17, input: 1.9, target: "double", base: 2.1, expectedCode: 3501300},
|
|
{_id: 19, input: "str", target: "string", base: 3, expectedCode: 3501301},
|
|
{
|
|
_id: 54,
|
|
input: ObjectId("0123456789abcdef01234567"),
|
|
target: "objectId",
|
|
base: 2.1,
|
|
expectedCode: 3501300,
|
|
},
|
|
{_id: 56, input: false, target: "bool", base: 3, expectedCode: 3501301},
|
|
{
|
|
_id: 57,
|
|
input: ISODate("1970-01-01T00:00:00.123Z"),
|
|
target: "date",
|
|
base: 2.1,
|
|
expectedCode: 3501300,
|
|
},
|
|
{_id: 59, input: NumberInt(1), target: "int", base: 3, expectedCode: 3501301},
|
|
{_id: 62, input: NumberLong(1), target: "long", base: 2.1, expectedCode: 3501300},
|
|
{_id: 63, input: NumberDecimal("1.9"), target: "decimal", base: 3, expectedCode: 3501301},
|
|
{_id: 65, input: NumberDecimal("1.9"), target: "decimal", base: 2.1, expectedCode: 3501300},
|
|
];
|
|
|
|
runConvertTests({
|
|
coll,
|
|
requiresFCV83,
|
|
runShorthandTests: false,
|
|
runRoundTripTests: true,
|
|
conversionTestDocs,
|
|
illegalConversionTestDocs,
|
|
invalidArgumentValueDocs,
|
|
});
|