pax_global_header00006660000000000000000000000064142302672710014516gustar00rootroot0000000000000052 comment=a9d0671dd8c74d3cba979d5049044aadc4b9baa3 bson-ruby-4.15.0/000077500000000000000000000000001423026727100135255ustar00rootroot00000000000000bson-ruby-4.15.0/.evergreen/000077500000000000000000000000001423026727100155655ustar00rootroot00000000000000bson-ruby-4.15.0/.evergreen/config.yml000066400000000000000000000510511423026727100175570ustar00rootroot00000000000000######################################## # Evergreen Template for MongoDB Drivers ######################################## # When a task that used to pass starts to fail # Go through all versions that may have been skipped to detect # when the task started failing stepback: true # Fail builds when pre tasks fail. pre_error_fails_task: true # Mark a failure as a system/bootstrap failure (purple box) rather then a task # failure by default. # Actual testing tasks are marked with `type: test` command_type: system # Protect ourself against rogue test case, or curl gone wild, that runs forever # 12 minutes is the longest we'll ever run exec_timeout_secs: 3600 # 12 minutes is the longest we'll ever run # What to do when evergreen hits the timeout (`post:` tasks are run automatically) timeout: - command: shell.exec params: script: | ls -la functions: "fetch source": # Executes git clone and applies the submitted patch, if any - command: git.get_project params: directory: "src" - command: shell.exec params: working_dir: "src" script: | set -ex git submodule update --init --recursive # Make an evergreen exapanstion file with dynamic values - command: shell.exec params: working_dir: "src" script: | # Get the current unique version of this checkout if [ "${is_patch}" = "true" ]; then CURRENT_VERSION=$(git describe)-patch-${version_id} else CURRENT_VERSION=latest fi export DRIVERS_TOOLS="$(pwd)/../drivers-tools" # Python has cygwin path problems on Windows. Detect prospective mongo-orchestration home directory if [ "Windows_NT" == "$OS" ]; then # Magic variable in cygwin export DRIVERS_TOOLS=$(cygpath -m $DRIVERS_TOOLS) fi export MONGO_ORCHESTRATION_HOME="$DRIVERS_TOOLS/.evergreen/orchestration" export MONGODB_BINARIES="$DRIVERS_TOOLS/mongodb/bin" export UPLOAD_BUCKET="${project}" export PROJECT_DIRECTORY="$(pwd)" cat < expansion.yml CURRENT_VERSION: "$CURRENT_VERSION" DRIVERS_TOOLS: "$DRIVERS_TOOLS" MONGO_ORCHESTRATION_HOME: "$MONGO_ORCHESTRATION_HOME" MONGODB_BINARIES: "$MONGODB_BINARIES" UPLOAD_BUCKET: "$UPLOAD_BUCKET" PROJECT_DIRECTORY: "$PROJECT_DIRECTORY" MACHINE: "$MACHINE" PREPARE_SHELL: | set -o errexit set -o xtrace export DRIVERS_TOOLS="$DRIVERS_TOOLS" export MONGO_ORCHESTRATION_HOME="$MONGO_ORCHESTRATION_HOME" export MONGODB_BINARIES="$MONGODB_BINARIES" export UPLOAD_BUCKET="$UPLOAD_BUCKET" export PROJECT_DIRECTORY="$PROJECT_DIRECTORY" export TMPDIR="$MONGO_ORCHESTRATION_HOME/db" export PATH="$MONGODB_BINARIES:$PATH" export PROJECT="${project}" export MACHINE="${MACHINE}" export CI=1 export WITH_ACTIVE_SUPPORT="${WITH_ACTIVE_SUPPORT}" export COMPACT="${COMPACT}" EOT # See what we've done cat expansion.yml # Load the expansion file to make an evergreen variable with the current unique version - command: expansions.update params: file: src/expansion.yml "prepare resources": - command: shell.exec params: script: | ${PREPARE_SHELL} rm -rf $DRIVERS_TOOLS if [ "${project}" = "drivers-tools" ]; then # If this was a patch build, doing a fresh clone would not actually test the patch cp -R ${PROJECT_DIRECTORY}/ $DRIVERS_TOOLS else git clone https://github.com/mongodb-labs/drivers-evergreen-tools $DRIVERS_TOOLS fi echo "{ \"releases\": { \"default\": \"$MONGODB_BINARIES\" }}" > $MONGO_ORCHESTRATION_HOME/orchestration.config "upload release": - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: ${project}.tar.gz remote_file: ${UPLOAD_BUCKET}/${project}-${CURRENT_VERSION}.tar.gz bucket: mciuploads permissions: public-read content_type: ${content_type|application/x-gzip} # Upload build artifacts that other tasks may depend on # Note this URL needs to be totally unique, while predictable for the next task # so it can automatically download the artifacts "upload build": # Compress and upload the entire build directory - command: archive.targz_pack params: # Example: mongo_c_driver_releng_9dfb7d741efbca16faa7859b9349d7a942273e43_16_11_08_19_29_52.tar.gz target: "${build_id}.tar.gz" source_dir: ${PROJECT_DIRECTORY}/ include: - "./**" - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: ${build_id}.tar.gz # Example: /mciuploads/${UPLOAD_BUCKET}/gcc49/9dfb7d741efbca16faa7859b9349d7a942273e43/debug-compile-nosasl-nossl/mongo_c_driver_releng_9dfb7d741efbca16faa7859b9349d7a942273e43_16_11_08_19_29_52.tar.gz remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${task_name}/${build_id}.tar.gz bucket: mciuploads permissions: public-read content_type: ${content_type|application/x-gzip} "fetch build": - command: shell.exec params: continue_on_err: true script: "set -o xtrace && rm -rf ${PROJECT_DIRECTORY}" - command: s3.get params: aws_key: ${aws_key} aws_secret: ${aws_secret} remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${BUILD_NAME}/${build_id}.tar.gz bucket: mciuploads local_file: build.tar.gz - command: shell.exec params: continue_on_err: true # EVG-1105: Use s3.get extract_to: ./ script: "set -o xtrace && cd .. && rm -rf ${PROJECT_DIRECTORY} && mkdir ${PROJECT_DIRECTORY}/ && tar xf build.tar.gz -C ${PROJECT_DIRECTORY}/" "exec compile script" : - command: shell.exec type: test params: working_dir: "src" script: | ${PREPARE_SHELL} [ -f ${PROJECT_DIRECTORY}/${file} ] && BUILDTOOL="${buildtool}" sh ${PROJECT_DIRECTORY}/${file} || echo "${PROJECT_DIRECTORY}/${file} not available, skipping" "exec script" : - command: shell.exec type: test params: working_dir: "src" script: | ${PREPARE_SHELL} [ -f ${PROJECT_DIRECTORY}/${file} ] && sh ${PROJECT_DIRECTORY}/${file} || echo "${PROJECT_DIRECTORY}/${file} not available, skipping" "upload docs" : - command: shell.exec params: silent: true script: | export AWS_ACCESS_KEY_ID=${aws_key} export AWS_SECRET_ACCESS_KEY=${aws_secret} aws s3 cp ${PROJECT_DIRECTORY}/doc/html s3://mciuploads/${UPLOAD_BUCKET}/docs/${CURRENT_VERSION} --recursive --acl public-read --region us-east-1 - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: ${PROJECT_DIRECTORY}/doc/html/index.html remote_file: ${UPLOAD_BUCKET}/docs/${CURRENT_VERSION}/index.html bucket: mciuploads permissions: public-read content_type: text/html display_name: "Rendered docs" "upload coverage" : - command: shell.exec params: silent: true script: | export AWS_ACCESS_KEY_ID=${aws_key} export AWS_SECRET_ACCESS_KEY=${aws_secret} aws s3 cp ${PROJECT_DIRECTORY}/coverage s3://mciuploads/${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/coverage/ --recursive --acl public-read --region us-east-1 - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: ${PROJECT_DIRECTORY}/coverage/index.html remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/coverage/index.html bucket: mciuploads permissions: public-read content_type: text/html display_name: "Coverage Report" "upload scan artifacts" : - command: shell.exec type: test params: script: | cd if find ${PROJECT_DIRECTORY}/scan -name \*.html | grep -q html; then (cd ${PROJECT_DIRECTORY}/scan && find . -name index.html -exec echo "
  • {}
  • " \;) >> scan.html else echo "No issues found" > scan.html fi - command: shell.exec params: silent: true script: | export AWS_ACCESS_KEY_ID=${aws_key} export AWS_SECRET_ACCESS_KEY=${aws_secret} aws s3 cp ${PROJECT_DIRECTORY}/scan s3://mciuploads/${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/scan/ --recursive --acl public-read --region us-east-1 - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: ${PROJECT_DIRECTORY}/scan.html remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/scan/index.html bucket: mciuploads permissions: public-read content_type: text/html display_name: "Scan Build Report" "upload mo artifacts": - command: shell.exec params: script: | ${PREPARE_SHELL} find $MONGO_ORCHESTRATION_HOME -name \*.log | xargs tar czf ${PROJECT_DIRECTORY}/mongodb-logs.tar.gz - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: ${PROJECT_DIRECTORY}/mongodb-logs.tar.gz remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/logs/${task_id}-${execution}-mongodb-logs.tar.gz bucket: mciuploads permissions: public-read content_type: ${content_type|application/x-gzip} display_name: "mongodb-logs.tar.gz" - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: ${DRIVERS_TOOLS}/.evergreen/orchestration/server.log remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/logs/${task_id}-${execution}-orchestration.log bucket: mciuploads permissions: public-read content_type: ${content_type|text/plain} display_name: "orchestration.log" "upload working dir": - command: archive.targz_pack params: target: "working-dir.tar.gz" source_dir: ${PROJECT_DIRECTORY}/ include: - "./**" - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: working-dir.tar.gz remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/artifacts/${task_id}-${execution}-working-dir.tar.gz bucket: mciuploads permissions: public-read content_type: ${content_type|application/x-gzip} display_name: "working-dir.tar.gz" - command: archive.targz_pack params: target: "drivers-dir.tar.gz" source_dir: ${DRIVERS_TOOLS} include: - "./**" - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: drivers-dir.tar.gz remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/artifacts/${task_id}-${execution}-drivers-dir.tar.gz bucket: mciuploads permissions: public-read content_type: ${content_type|application/x-gzip} display_name: "drivers-dir.tar.gz" "upload test results": - command: attach.xunit_results params: file: ./src/*/build/test-results/TEST-*.xml "bootstrap mongo-orchestration": - command: shell.exec params: script: | ${PREPARE_SHELL} MONGODB_VERSION=${VERSION} TOPOLOGY=${TOPOLOGY} AUTH=${AUTH} SSL=${SSL} sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh # run-orchestration generates expansion file with the MONGODB_URI for the cluster - command: expansions.update params: file: mo-expansion.yml "run tests": - command: shell.exec type: test params: shell: bash working_dir: "src" script: | ${PREPARE_SHELL} RVM_RUBY="${RVM_RUBY}" .evergreen/run-tests.sh "cleanup": - command: shell.exec params: script: | ${PREPARE_SHELL} cd "$MONGO_ORCHESTRATION_HOME" # source the mongo-orchestration virtualenv if it exists if [ -f venv/bin/activate ]; then . venv/bin/activate elif [ -f venv/Scripts/activate ]; then . venv/Scripts/activate fi mongo-orchestration stop cd - rm -rf $DRIVERS_TOOLS || true "fix absolute paths": - command: shell.exec params: script: | ${PREPARE_SHELL} for filename in $(find ${DRIVERS_TOOLS} -name \*.json); do perl -p -i -e "s|ABSOLUTE_PATH_REPLACEMENT_TOKEN|${DRIVERS_TOOLS}|g" $filename done "windows fix": - command: shell.exec params: script: | ${PREPARE_SHELL} for i in $(find ${DRIVERS_TOOLS}/.evergreen ${PROJECT_DIRECTORY}/.evergreen -name \*.sh); do cat $i | tr -d '\r' > $i.new mv $i.new $i done "make files executable": - command: shell.exec params: script: | ${PREPARE_SHELL} for i in $(find ${DRIVERS_TOOLS}/.evergreen ${PROJECT_DIRECTORY}/.evergreen -name \*.sh); do chmod +x $i done "init test-results": - command: shell.exec params: script: | ${PREPARE_SHELL} echo '{"results": [{ "status": "FAIL", "test_file": "Build", "log_raw": "No test-results.json found was created" } ]}' > ${PROJECT_DIRECTORY}/test-results.json "install dependencies": - command: shell.exec type: test params: working_dir: "src" script: | ${PREPARE_SHELL} file="${PROJECT_DIRECTORY}/.evergreen/install-dependencies.sh" [ -f ${file} ] && sh ${file} || echo "${file} not available, skipping" pre: - func: "fetch source" - func: "prepare resources" - func: "windows fix" - func: "fix absolute paths" - func: "init test-results" - func: "make files executable" - func: "install dependencies" post: # Removed, causing timeouts #- func: "upload working dir" - func: "upload mo artifacts" - func: "upload test results" - func: "cleanup" tasks: - name: "test" commands: - func: "run tests" axes: - id: "topology" display_name: Topology values: - id: "standalone" display_name: Standalone variables: TOPOLOGY: "server" - id: "replicaset" display_name: Replica Set variables: TOPOLOGY: "replica_set" - id: "sharded-cluster" display_name: Sharded Cluster variables: TOPOLOGY: "sharded_cluster" - id: "auth" display_name: Authentication values: - id: "auth" display_name: Auth variables: AUTH: "auth" - id: "noauth" display_name: NoAuth variables: AUTH: "noauth" - id: "ssl" display_name: SSL values: - id: "ssl" display_name: SSL variables: SSL: "ssl" - id: "nossl" display_name: NoSSL variables: SSL: "nossl" - id: "all-os" display_name: OS values: - id: "debian92" display_name: "Debian 9 x86" run_on: debian92-small variables: MACHINE: "debian92" - id: "ubuntu1604" display_name: "Ubuntu 16.04" run_on: ubuntu1604-small variables: MACHINE: "ubuntu1604" - id: "ubuntu1804" display_name: "Ubuntu 18.04" run_on: ubuntu1804-small variables: MACHINE: "ubuntu1804" - id: "rhel70" display_name: "RHEL 7.0" run_on: rhel70-small variables: MACHINE: "rhel70" - id: "special-os" display_name: OS values: #- id: "rhel71-ppc" # display_name: "RHEL 7.1 PowerPC" # run_on: rhel71-power8-small # variables: # MACHINE: "rhel71-ppc" - id: "ubuntu1804-ppc" display_name: "Ubuntu 18.04 PowerPC" run_on: ubuntu1804-power8-small variables: MACHINE: ubuntu1804-ppc - id: "ubuntu1604-arm" display_name: "Ubuntu 16.04 ARM64" run_on: ubuntu1604-arm64-small variables: MACHINE: "ubuntu1604-arm" - id: "ubuntu1804-arm" display_name: "Ubuntu 18.04 ARM64" run_on: ubuntu1804-arm64-small variables: MACHINE: "ubuntu1804-arm" - id: "mri-rubies" display_name: Ruby Version values: - id: "ruby-2.5" display_name: ruby-2.5 variables: RVM_RUBY: "ruby-2.5" - id: "ruby-2.6" display_name: ruby-2.6 variables: RVM_RUBY: "ruby-2.6" - id: "ruby-2.7" display_name: ruby-2.7 variables: RVM_RUBY: "ruby-2.7" - id: "ruby-3.0" display_name: ruby-3.0 variables: RVM_RUBY: "ruby-3.0" - id: "ruby-3.1" display_name: ruby-3.1 variables: RVM_RUBY: "ruby-3.1" - id: "jruby-rubies" display_name: Ruby Version values: - id: "jruby-9.2" display_name: jruby-9.2 variables: RVM_RUBY: "jruby-9.2" - id: "jruby-9.3" display_name: jruby-9.3 variables: RVM_RUBY: "jruby-9.3" - id: "ruby-head" display_name: Ruby Head values: - id: "ruby-head" display_name: ruby-head variables: RVM_RUBY: "ruby-head" - id: "as" display_name: ActiveSupport values: - id: "5.1" display_name: 5.1 variables: WITH_ACTIVE_SUPPORT: "~> 5.1.0" - id: "5.2" display_name: 5.2 variables: WITH_ACTIVE_SUPPORT: "~> 5.2.0" - id: "6.0" display_name: 6.0 variables: WITH_ACTIVE_SUPPORT: "~> 6.0.0" - id: "6.1" display_name: 6.1 variables: WITH_ACTIVE_SUPPORT: "~> 6.1.0" - id: "7.0" display_name: 7.0 variables: WITH_ACTIVE_SUPPORT: "~> 7.0.0" - id: "compact" display_name: GC.compact values: - id: "on" display_name: with GC.compact variables: COMPACT: true buildvariants: - matrix_name: "mri-rhel" matrix_spec: { mri-rubies: [ruby-2.5], all-os: "rhel70" } display_name: "${mri-rubies}, ${all-os}" tasks: - name: "test" - matrix_name: "mri-debian" matrix_spec: { mri-rubies: [ruby-2.7], all-os: "debian92" } display_name: "${mri-rubies}, ${all-os}" tasks: - name: "test" - matrix_name: "mri-ubuntu" matrix_spec: { mri-rubies: [ruby-2.5], all-os: "ubuntu1604" } display_name: "${mri-rubies}, ${all-os}" tasks: - name: "test" - matrix_name: "mri-ubuntu-ruby3" matrix_spec: { mri-rubies: ["ruby-3.0", "ruby-3.1"], all-os: ubuntu1804 } display_name: "${mri-rubies}, ${all-os}" tasks: - name: "test" - matrix_name: "activesupport-5-6" matrix_spec: mri-rubies: [ruby-2.5, ruby-2.6, ruby-2.7, ruby-3.0] all-os: "ubuntu1804" as: ['5.1', '5.2', '6.0', '6.1'] display_name: "AS ${as} ${mri-rubies}, ${all-os}" tasks: - name: "test" - matrix_name: "activesupport-7" matrix_spec: # Rails 7 requires Ruby 2.7 mri-rubies: [ruby-2.7, ruby-3.0] all-os: "ubuntu1804" as: ['7.0'] display_name: "AS ${as} ${mri-rubies}, ${all-os}" tasks: - name: "test" - matrix_name: "activesupport-old-rubies" matrix_spec: mri-rubies: [ruby-2.5] all-os: "ubuntu1604" as: ['5.1', '5.2'] display_name: "AS ${as} ${mri-rubies}, ${all-os}" tasks: - name: "test" - matrix_name: "special-os" matrix_spec: { mri-rubies: ruby-2.7, special-os: [ubuntu1604-arm, ubuntu1804-ppc] } display_name: "${mri-rubies}, ${special-os}" tasks: - name: "test" # - matrix_name: "ruby-head" # matrix_spec: { ruby-head: "*", all-os: ["ubuntu1604"] } # display_name: "${ruby-head}, ${all-os}" # tasks: # - name: "test" - matrix_name: "jruby" matrix_spec: { jruby-rubies: "*", all-os: ["rhel70"] } display_name: "${jruby-rubies}, ${all-os}" tasks: - name: "test" - matrix_name: "compact" matrix_spec: mri-rubies: [ruby-2.7, ruby-3.0] all-os: "ubuntu1804" compact: "on" display_name: "${mri-rubies} with GC.compact" tasks: - name: "test" bson-ruby-4.15.0/.evergreen/functions.sh000066400000000000000000000016621423026727100201360ustar00rootroot00000000000000set_home() { if test -z "$HOME"; then export HOME=$(pwd) fi } set_env_vars() { export CI=evergreen # JRUBY_OPTS were initially set for Mongoid export JRUBY_OPTS="--server -J-Xms512m -J-Xmx2G" if test "$BSON" = min; then export BUNDLE_GEMFILE=gemfiles/bson_min.gemfile elif test "$BSON" = master; then export BUNDLE_GEMFILE=gemfiles/bson_master.gemfile fi } bundle_install() { #which bundle #bundle --version args=--quiet if test -n "$BUNDLE_GEMFILE"; then args="$args --gemfile=$BUNDLE_GEMFILE" fi echo "Running bundle install $args" bundle install $args } install_deps() { bundle_install bundle exec rake clean } kill_jruby() { jruby_running=`ps -ef | grep 'jruby' | grep -v grep | awk '{print $2}'` if [ -n "$jruby_running" ];then echo "terminating remaining jruby processes" for pid in $(ps -ef | grep "jruby" | grep -v grep | awk '{print $2}'); do kill -9 $pid; done fi } bson-ruby-4.15.0/.evergreen/run-tests.sh000066400000000000000000000011641423026727100200670ustar00rootroot00000000000000#!/bin/bash set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail # Supported/used environment variables: # RVM_RUBY Define the Ruby version to test with, using its RVM identifier. # For example: "ruby-2.4" or "jruby-9.2" . `dirname "$0"`/../spec/shared/shlib/distro.sh . `dirname "$0"`/../spec/shared/shlib/set_env.sh . `dirname "$0"`/functions.sh set_env_vars set_env_ruby install_deps echo "Running specs" bundle exec rake spec test_status=$? echo "TEST STATUS" echo ${test_status} kill_jruby exit ${test_status} bson-ruby-4.15.0/.github/000077500000000000000000000000001423026727100150655ustar00rootroot00000000000000bson-ruby-4.15.0/.github/workflows/000077500000000000000000000000001423026727100171225ustar00rootroot00000000000000bson-ruby-4.15.0/.github/workflows/bson-ruby.yml000066400000000000000000000023371423026727100215720ustar00rootroot00000000000000name: CI on: [push, pull_request] jobs: build: name: >- ${{ matrix.os }} ${{ matrix.ruby }} env: CI: true TESTOPTS: -v runs-on: ${{ matrix.os }}-latest if: | !( contains(github.event.pull_request.title, '[ci skip]') || contains(github.event.pull_request.title, '[skip ci]') || contains(github.event.head_commit.message, '[ci skip]') || contains(github.event.head_commit.message, '[skip ci]')) strategy: fail-fast: false matrix: os: [ ubuntu, macos, windows ] ruby: [ 2.5, 2.6, 2.7, 3.0, 3.1, head ] include: - { os: windows , ruby: mingw } exclude: - { os: windows , ruby: head } - { os: windows , ruby: 3.1 } steps: - name: repo checkout uses: actions/checkout@v2 with: submodules: recursive - name: load ruby, ragel uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler: 2 - name: bundle install run: bundle install --jobs 4 --retry 3 - name: compile run: bundle exec rake compile - name: test timeout-minutes: 10 run: bundle exec rake spec bson-ruby-4.15.0/.gitignore000066400000000000000000000004751423026727100155230ustar00rootroot00000000000000Gemfile.lock build/* *.swp .#* \#*# *__pycache__* *.pyc *.pyo *.bak .DS_Store .rvmrc tmp/* *.o *.bundle *.so core .idea/ *.gem perf/profile.rb perf/*.pdf perf/*.profile perf/*.symbols TODO .rbx/ gem-private_key.pem .ruby-version .ruby-gemset yard-docs lib/*.jar .yardoc .byebug_history .env .env.private* docs/_build bson-ruby-4.15.0/.gitmodules000066400000000000000000000001541423026727100157020ustar00rootroot00000000000000[submodule "spec/shared"] path = spec/shared url = https://github.com/mongodb-labs/mongo-ruby-spec-shared bson-ruby-4.15.0/.rspec000066400000000000000000000001001423026727100146310ustar00rootroot00000000000000--color --format <%= ENV["CI"] ? 'Rfc::Riff' : 'Fuubar'%> --tty bson-ruby-4.15.0/.yardopts000066400000000000000000000000451423026727100153720ustar00rootroot00000000000000lib/**/*.rb ext/bson/*.c -o yard-docsbson-ruby-4.15.0/CHANGELOG.md000066400000000000000000000157731423026727100153530ustar00rootroot00000000000000BSON Changelog ============== ## 3.2.6 ### Bug Fixes * [#44](https://github.com/mongodb/bson-ruby/pull/44) Fixed regexp deserialization in conjunction with SSL io. (Niels Ganser) ## 3.2.5 ### Bug Fixes * [RUBY-1024](https://jira.mongodb.org/browse/RUBY-1024) Fixed Hash#merge only to yield when keys exist in both hashes. (Agis Anastasopoulos) ## 3.2.4 ### Bug Fixes * [RUBY-1019](https://jira.mongodb.org/browse/RUBY-1019) Performace improvements on deserialization. ## 3.2.3 ### Bug Fixes * [#41](https://github.com/mongodb/bson-ruby/pull/41) Normalizing arrays does not mutate. (Agis Anastasopoulos) * [#40](https://github.com/mongodb/bson-ruby/pull/40) Added big endian support. (Jeff Blight) ## 3.2.1 ### Bug Fixes [#39](https://github.com/mongodb/bson-ruby/pull/39) Fixed MD5 hashing of hostname in c extension. (James Hudon) ## 3.2.0 ### Bug Fixes * [RUBY-950](https://jira.mongodb.org/browse/RUBY-950) Don't encode to UTF-8 in Binary#to_bson, only force BINARY encoding. ### New features * Add `BSON.ObjectId` constructor for instantiating an ObjectId from a String. Update ObjectId#inspect to print out a string that can be evaluated into the corresponding ObjectId. (Tony Ta) ## 3.1.2 ### Bug Fixes * [RUBY-950](https://jira.mongodb.org/browse/RUBY-950) Encode to UTF-8 then force BINARY encoding in Binary#to_bson. ## 3.1.1 ### Bug Fixes * Fixed argument errors when delegating to regex objects. (Tom Scott) ## 3.1.0 ### New Features * `BSON::Regexp::Raw` now behaves like a regular `Regexp` by delegating to the compiled and wrapped regex. (Tom Scott) ### Bug Fixes * Fixed `inspect` on `BSON::Binary` to handle ASCII characters. (Jérémy Carlier) ## 3.0.4 ### Bug Fixes * Fixed `BSON::ObjectId.legal?` regular expression to properly check beginning and end of strings. ## 3.0.3 ### Bug Fixes * [#31](https://github.com/mongodb/bson-ruby/pull/31) Fix Int64 decode from strings. (Nobuyoshi Nakada) ## 3.0.2 ### Bug Fixes * [RUBY-898](https://jira.mongodb.org/browse/RUBY-898) Compensated for different return values of Socket#readbyte and OpenSSL::SSL::SSLSocket#readbyte. ## 3.0.1 ### Bug Fixes * Fixed installation on latest Rubygems which requires `'date'` to be required. ## 3.0.0 ### Backwards Incompatible Changes * [RUBY-852](https://jira.mongodb.org/browse/RUBY-852) Regular expressions that are deserialized now return a `BSON::Regexp::Raw` instead of a `Regexp` object. In order to get the regular expression compiled, call `#compile` on the returned object. raw.compile ### New Features * `BSON::Binary` now implements `#inspect` with a truncated view of the data for better readability. ### Bug Fixes * The native object id generation was fixed to match the raw Ruby. (Conrad Irwin) * [#23](http://github.com/mongodb/bson-ruby/pull/23): `BSON::Binary` types can be now used as hash keys. (Adam Wróbel) ## 2.2.3 ### Bug Fixes * Fixed native C encoding of strings and performace on Rubinius. ## 2.2.2 ### Bug Fixes * [#17](http://github.com/mongodb/bson-ruby/pull/17): Fixed `BSON::ObjectId` counter increment on Ruby 2.1.0 since method names can no longer override Ruby keywords. * [#16](http://github.com/mongodb/bson-ruby/pull/16): Fixed serialization of times when microseconds are causing `to_f` on time to be 1 microsecond inaccurate. (Francois Bernier) ## 2.2.1 ### Bug Fixes * [#15](http://github.com/mongodb/bson-ruby/pull/15): `Date` and `DateTime` instances now return the `Time` value for the BSON type, so that they can be serialized inside hashes and arrays. (Michael Sell) ## 2.2.0 ### Dependency Changes * Ruby 1.8 interpreters are no longer supported. ## 2.1.2 ### Bug Fixes * [#14](http://github.com/mongodb/bson-ruby/pull/14): Fixed all 1.8 errors related to `DateTime` serialization. ## 2.1.1 ### Bug Fixes * [#13](http://github.com/mongodb/bson-ruby/pull/13) / [RUBY-714](http://jira.mongodb.org/browse/RUBY-714): Require time in `DateTime` modules when using outside of environments that don't already have time included. ## 2.1.0 ### New Features * `Date` and `DateTime` objects in Ruby can now be serialized into BSON. `Date` is converted to a UTC `Time` at midnight and serialized, while `DateTime` is simply converted to the identical `Time` before serialization. Note that these objects will be deserialized into `Time` objects. ## 2.0.0 ### Backwards Incompatible Changes * `BSON::DEFAULT_MAX_BSON_SIZE` has been removed, as the BSON specification does not provide an upper limit on how large BSON documents can be. * `BSON.serialize` is no longer the entry point to serialize a BSON document into its raw bytes. For Ruby runtimes that support ordered hashes, you may simply call `to_bson` on the hash instance (Alternatively a `BSON::Document` is also a hash: { key: "value" }.to_bson BSON::Document[:key, "value"].to_bson For Ruby runtimes that do not support ordered hashes, then you must instantiate an instance of a `BSON::Document` (which is a subclass of hash) and call `to_bson` on that, since the BSON specification guarantees order of the fields: BSON::Document[:key, "value"].to_bson * `BSON.deserialize` is no longer the entry point for raw byte deserialization into a document. For Ruby runtimes that support ordered hashes, you may simply call `from_bson` on the `Hash` class if you want a `Hash` instance, or on `BSON::Document` if you want an instance of that. The input must be a `StringIO` object: Hash.from_bson(stringio) BSON::Document.from_bson(stringio) For Ruby runtimes that do not support ordered hashes, then `from_bson` must be called on `BSON::Document` in order to guarantee order: BSON::Document.from_bson(stringio) * Calling `to_json` on custom BSON objects now outputs different results from before, and conforms the BSON specification: - `BSON::Binary`: `{ "$binary" : "\x01", "$type" : "md5" }` - `BSON::Code`: `{ "$code" : "this.v = 5 }` - `BSON::CodeWithScope`: `{ "$code" : "this.v = value", "$scope" : { v => 5 }}` - `BSON::MaxKey`: `{ "$maxKey" : 1 }` - `BSON::MinKey`: `{ "$minKey" : 1 }` - `BSON::ObjectId`: `{ "$oid" : "4e4d66343b39b68407000001" }` - `BSON::Timestamp`: `{ "t" : 5, "i" : 30 }` - `Regexp`: `{ "$regex" : "[abc]", "$options" : "i" }` ### New Features * All Ruby objects that have a corresponding object defined in the BSON specification can now have `to_bson` called on them to get the raw BSON bytes. These objects include: - `Array` - `FalseClass` - `Float` - `Hash` - `Integer` - `NilClass` - `Regexp` - `String` - `Symbol` (deprecated) - `Time` - `TrueClass` * Custom types specific to the BSON specification that have Ruby objects defined for them may also have `to_bson` called on them to get the raw bytes. These types are: - `BSON::Binary` - `BSON::Code` - `BSON::CodeWithScope` - `BSON::MaxKey` - `BSON::MinKey` - `BSON::ObjectId` - `BSON::Timestamp` - `BSON::Undefined` bson-ruby-4.15.0/CONTRIBUTING.md000066400000000000000000000023641423026727100157630ustar00rootroot00000000000000Contributing ============ Code Conventions ---------------- Code style should fall in line with the style guide outlined by [Github](https://github.com/styleguide/ruby) Testing ------- Bug fixes and new features should always have the appropriate specs, and the specs should follow the following guidelines: - Prefer `let` and `let!` over the use of instance variables and `subject`. - Prefer `expect(...).to eq(...) syntax over `...should eq(...)`. - Use shared examples to reduce duplication. - Use `describe "#method"` for instance method specs. - Use `describe ".method"` for class method specs. - Use `context` blocks to set up conditions. - Always provide descriptive specifications via `it`. Specs can be automatically run with Guard, via `bundle exec guard` Before commiting, run `rake` to ensure all specs pass with both pure Ruby and the native extensions. Git Etiquette ------------- Please follow the commit message guidelines as outlined [in this blog post](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). If the commit fixes a bug, please add the JIRA number on the last line: ``` [ close RUBY-492 ] ``` Please ensure that only one feature/bug fix is in each pull request, and that it is squashed into a single commit. bson-ruby-4.15.0/Gemfile000066400000000000000000000010451423026727100150200ustar00rootroot00000000000000source 'https://rubygems.org' gemspec group :development, :test do gem 'rake' gem 'rake-compiler' gem 'yard' gem 'rspec', '~> 3' gem 'json' if ENV['WITH_ACTIVE_SUPPORT'] =~ /[0-9]/ && ENV['WITH_ACTIVE_SUPPORT'] != '0' gem 'activesupport', ENV['WITH_ACTIVE_SUPPORT'] else gem 'activesupport', '<7.1' end gem 'ruby-prof', platforms: :mri gem 'byebug', platforms: :mri # https://github.com/jruby/jruby/wiki/UsingTheJRubyDebugger gem 'ruby-debug', platforms: :jruby end group :test do gem 'fuubar' gem 'rfc' end bson-ruby-4.15.0/LICENSE000066400000000000000000000250171423026727100145370ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright (C) 2008-2013 MongoDB, Inc. 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. bson-ruby-4.15.0/NOTICE000066400000000000000000000000601423026727100144250ustar00rootroot00000000000000Ruby BSON Copyright (C) 2009-2013 MongoDB, Inc. bson-ruby-4.15.0/README.md000066400000000000000000000037611423026727100150130ustar00rootroot00000000000000BSON [![Gem Version][rubygems-img]][rubygems-url] [![Build Status][ghactions-img]][ghactions-url] [![Coverage Status][coveralls-img]][coveralls-url] [![Inline docs][inch-img]][inch-url] ==== An implementation of the BSON specification in Ruby. Compatibility ------------- BSON is tested against MRI (2.5) and JRuby (9.2+). Documentation ------------- Current documentation can be found [here](http://docs.mongodb.org/ecosystem/tutorial/ruby-bson-tutorial/#ruby-bson-tutorial). API Documentation ----------------- The [API Documentation](https://api.mongodb.com/bson-ruby/current/) is located at api.mongodb.com. BSON Specification ------------------ The [BSON specification](http://bsonspec.org) is at bsonspec.org. Versioning ---------- As of 2.0.0, this project adheres to the [Semantic Versioning Specification](http://semver.org/). License ------- Copyright (C) 2009-2020 MongoDB Inc. 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. [rubygems-img]: https://badge.fury.io/rb/bson.svg [rubygems-url]: http://badge.fury.io/rb/bson [ghactions-img]: https://github.com/mongodb/bson-ruby/actions/workflows/bson-ruby.yml/badge.svg?query=branch%3Amaster [ghactions-url]: https://github.com/mongodb/bson-ruby/actions/workflows/bson-ruby.yml?query=branch%3Amaster [coveralls-img]: https://coveralls.io/repos/mongodb/bson-ruby/badge.svg?branch=master [coveralls-url]: https://coveralls.io/r/mongodb/bson-ruby?branch=master [inch-img]: http://inch-ci.org/github/mongodb/bson-ruby.svg?branch=master [inch-url]: http://inch-ci.org/github/mongodb/bson-ruby bson-ruby-4.15.0/Rakefile000066400000000000000000000062621423026727100152000ustar00rootroot00000000000000# Copyright (C) 2009-2013 MongoDB Inc. # # 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. require "bundler" Bundler.setup $LOAD_PATH.unshift(File.expand_path("../lib", __FILE__)) require "rake" require "rake/extensiontask" require "rspec/core/rake_task" require 'fileutils' def jruby? defined?(JRUBY_VERSION) end if jruby? require "rake/javaextensiontask" Rake::JavaExtensionTask.new do |ext| ext.name = "bson-ruby" ext.ext_dir = "src" ext.lib_dir = "lib" end else require "rake/extensiontask" Rake::ExtensionTask.new do |ext| ext.name = "bson_native" ext.ext_dir = "ext/bson" ext.lib_dir = "lib" end end require "bson/version" def extension RUBY_PLATFORM =~ /darwin/ ? "bundle" : "so" end require_relative "perf/bench" RSpec::Core::RakeTask.new(:rspec) if jruby? task :build => [ :clean_all, :compile ] do system "gem build bson.gemspec" end else task :build => :clean_all do system "gem build bson.gemspec" end end task :clean_all => :clean do FileUtils.rm_f(File.join(File.dirname(__FILE__), 'lib', "bson_native.#{extension}")) FileUtils.rm_f(File.join(File.dirname(__FILE__), 'lib', "bson_native.o")) FileUtils.rm_f(File.join(File.dirname(__FILE__), 'lib', "bson-ruby.jar")) end task :spec => :compile do Rake::Task["rspec"].invoke end # Run bundle exec rake release with mri and jruby. Ex: # # rvm use 2.1.0@bson # bundle exec rake release # rvm use jruby@bson # bundle exec rake release task :release => :build do system "git tag -a v#{BSON::VERSION} -m 'Tagging release: #{BSON::VERSION}'" system "git push --tags" if jruby? system "gem push bson-#{BSON::VERSION}-java.gem" system "rm bson-#{BSON::VERSION}-java.gem" else system "gem push bson-#{BSON::VERSION}.gem" system "rm bson-#{BSON::VERSION}.gem" end end namespace :benchmark do task :ruby => :clean_all do puts "Benchmarking pure Ruby..." require "bson" benchmark! end task :native => :compile do puts "Benchmarking with native extensions..." require "bson" benchmark! end namespace :decimal128 do task :from_string do puts "Benchmarking creating Decimal128 objects from a string" require 'bson' benchmark_decimal128_from_string! end task :to_string do puts "Benchmarking getting a string representation of a Decimal128" require 'bson' benchmark_decimal128_to_string! end end end task :default => [ :clean_all, :spec ] desc "Generate all documentation" task :docs => 'docs:yard' namespace :docs do desc "Generate yard documention" task :yard do out = File.join('yard-docs', BSON::VERSION) FileUtils.rm_rf(out) system "yardoc -o #{out} --title bson-#{BSON::VERSION}" end end bson-ruby-4.15.0/bson.gemspec000066400000000000000000000033101423026727100160300ustar00rootroot00000000000000lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'bson/version' Gem::Specification.new do |s| s.name = 'bson' s.version = BSON::VERSION s.authors = ['Tyler Brock', 'Durran Jordan', 'Brandon Black', 'Emily Stolfo', 'Gary Murakami'] s.homepage = 'https://docs.mongodb.com/ruby-driver/current/tutorials/bson-v4/' s.summary = 'Ruby implementation of the BSON specification' s.description = 'A fully featured BSON specification implementation in Ruby' s.license = 'Apache-2.0' s.metadata = { 'bug_tracker_uri' => 'https://jira.mongodb.org/projects/RUBY', 'changelog_uri' => 'https://github.com/mongodb/bson-ruby/releases', 'documentation_uri' => 'https://docs.mongodb.com/ruby-driver/current/tutorials/bson-v4/', 'homepage_uri' => 'https://docs.mongodb.com/ruby-driver/current/tutorials/bson-v4/', 'source_code_uri' => 'https://github.com/mongodb/bson-ruby' } if File.exist?('gem-private_key.pem') s.signing_key = 'gem-private_key.pem' s.cert_chain = ['gem-public_cert.pem'] else warn "[#{s.name}] Warning: No private key present, creating unsigned gem." end s.files = %w(CONTRIBUTING.md CHANGELOG.md LICENSE NOTICE README.md Rakefile) s.files += Dir.glob('lib/**/*') unless RUBY_PLATFORM =~ /java/ s.platform = Gem::Platform::RUBY s.files += Dir.glob('ext/**/*.{c,h,rb}') s.extensions = ['ext/bson/extconf.rb'] else s.platform = 'java' end s.test_files = Dir.glob('spec/**/*') s.require_path = 'lib' s.required_ruby_version = '>= 2.5' s.required_rubygems_version = '>= 1.3.6' end bson-ruby-4.15.0/docs/000077500000000000000000000000001423026727100144555ustar00rootroot00000000000000bson-ruby-4.15.0/docs/Makefile000066400000000000000000000011721423026727100161160ustar00rootroot00000000000000# Minimal makefile for Sphinx documentation # # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) bson-ruby-4.15.0/docs/README.md000066400000000000000000000011331423026727100157320ustar00rootroot00000000000000Ruby BSON Documentation ======================= This subdirectory contains the high-level driver documentation, including tutorials and the reference. Building the documentation for publishing is done via the [docs-ruby repo](https://github.com/mongodb/docs-ruby). To build the documentation locally for review, install `sphinx` and `sphinx-book-theme`, then execute `make html` in this directory: pip install sphinx sphinx-book-theme make html Note that the documentation generated in this manner wouldn't have the BSON documentation included, nor are intersphinx links currently handled. bson-ruby-4.15.0/docs/bson-tutorials.txt000066400000000000000000000006231423026727100202040ustar00rootroot00000000000000==== BSON ==== .. default-domain:: mongodb This section contains tutorials for using the core Ruby BSON gem. The Ruby BSON implementation is packaged in a separate gem with C and Java extensions for speed depending on the runtime enviroment. .. toctree:: :titlesonly: /tutorials/bson-v4 /tutorials/bson-v3 .. seealso:: `BSON Source Code on GitHub `_ bson-ruby-4.15.0/docs/conf.py000066400000000000000000000035751423026727100157660ustar00rootroot00000000000000# Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. For a full # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) # -- Project information ----------------------------------------------------- project = 'Ruby BSON' copyright = '2021, MongoDB' # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'alabaster' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] source_suffix = { '.txt': 'restructuredtext', } html_theme = 'sphinx_book_theme' bson-ruby-4.15.0/docs/index.txt000077700000000000000000000000001423026727100223772tutorials/bson-v4.txtustar00rootroot00000000000000bson-ruby-4.15.0/docs/tutorials/000077500000000000000000000000001423026727100165035ustar00rootroot00000000000000bson-ruby-4.15.0/docs/tutorials/bson-v3.txt000066400000000000000000000113421423026727100205340ustar00rootroot00000000000000.. http://docs.mongodb.org/ecosystem/tutorial/ruby-bson-tutorial/ .. _ruby-bson-tutorial: ***************** BSON 3.x Tutorial ***************** .. default-domain:: mongodb .. contents:: On this page :local: :backlinks: none :depth: 1 :class: twocols This tutorial discusses using the core Ruby BSON gem. Installation ============ The BSON library is hosted on `Rubygems `_ and can be installed manually or with bundler. To install the gem manually: .. code-block:: sh gem install bson -v '~> 3.0' To install the gem with bundler, include the following in your ``Gemfile``: .. code-block:: ruby gem 'bson', '~> 3.0' The BSON gem is compatible with MRI 1.9.3, 2.0.x, 2.1.x, 2.2.x, JRuby 1.7.x, and Rubinius 2.5.x BSON Serialization ================== Getting a Ruby object's raw BSON representation is done by calling ``to_bson`` on the Ruby object. For example: .. code-block:: ruby "Shall I compare thee to a summer's day".to_bson 1024.to_bson Generating an object from BSON is done via calling ``from_bson`` on the class you wish to instantiate and passing it the ``StringIO`` bytes. .. code-block:: ruby String.from_bson(string_io) Int32.from_bson(string_io) Core Ruby objects that are represented in the BSON specification and have a ``to_bson`` method defined for them are: - ``Object`` - ``Array`` - ``FalseClass`` - ``Float`` - ``Hash`` - ``Integer`` - ``NilClass`` - ``Regexp`` - ``String`` - ``Symbol`` (deprecated) - ``Time`` - ``TrueClass`` In addition to the core Ruby objects, BSON also provides some special types specific to the specification: ``BSON::Binary`` ---------------- This is a representation of binary data, and must provide the raw data and a subtype when constructing. .. code-block:: ruby BSON::Binary.new(binary_data, :md5) Valid subtypes are: - ``:generic`` - ``:function`` - ``:old`` - ``:uuid_old`` - ``:uuid`` - ``:md5`` - ``:user`` ``BSON::Code`` -------------- Represents a string of Javascript code. .. code-block:: ruby BSON::Code.new("this.value = 5;") ``BSON::CodeWithScope`` ----------------------- Represents a string of Javascript code with a hash of values. .. code-block:: ruby BSON::CodeWithScope.new("this.value = age;", age: 5) ``BSON::Document`` ------------------ This is a subclass of a hash that stores all keys as strings but allows access to them with symbol keys. .. code-block:: ruby BSON::Document[:key, "value"] BSON::Document.new ``BSON::MaxKey`` ---------------- Represents a value in BSON that will always compare higher to another value. .. code-block:: ruby BSON::MaxKey.new ``BSON::MinKey`` ---------------- Represents a value in BSON that will always compare lower to another value. .. code-block:: ruby BSON::MinKey.new ``BSON::ObjectId`` ------------------ Represents a 12 byte unique identifier for an object on a given machine. .. code-block:: ruby BSON::ObjectId.new ``BSON::Timestamp`` ------------------- Represents a special time with a start and increment value. .. code-block:: ruby BSON::Timestamp.new(5, 30) ``BSON::Undefined`` ------------------- Represents a placeholder for a value that was not provided. .. code-block:: ruby BSON::Undefined.new JSON Serialization ================== Some BSON types have special representations in JSON. These are as follows and will be automatically serialized in the form when calling ``to_json`` on them. .. list-table:: :header-rows: 1 :widths: 40 105 * - Object - JSON * - ``BSON::Binary`` - ``{ "$binary" : "\x01", "$type" : "md5" }`` * - ``BSON::Code`` - ``{ "$code" : "this.v = 5" }`` * - ``BSON::CodeWithScope`` - ``{ "$code" : "this.v = value", "$scope" : { v => 5 }}`` * - ``BSON::MaxKey`` - ``{ "$maxKey" : 1 }`` * - ``BSON::MinKey`` - ``{ "$minKey" : 1 }`` * - ``BSON::ObjectId`` - ``{ "$oid" : "4e4d66343b39b68407000001" }`` * - ``BSON::Timestamp`` - ``{ "t" : 5, "i" : 30 }`` * - ``Regexp`` - ``{ "$regex" : "[abc]", "$options" : "i" }`` Special Ruby Date Classes ========================= Ruby's ``Date`` and ``DateTime`` are able to be serialized, but when they are deserialized they will always be returned as a ``Time`` since the BSON specification only has a ``Time`` type and knows nothing about Ruby. Compiling Regexes ================= When regular expressions are deserialized, they return a wrapper that holds the raw regex string, but does not compile it. In order to get the Ruby ``Regexp`` object, one must call ``compile`` on the returned object. .. code-block:: ruby regex = Regexp.from_bson(io) regex.pattern # Returns the pattern as a string. regex.options # Returns the raw options as an int. regex.compile # Returns the compiled Ruby Regexp object. bson-ruby-4.15.0/docs/tutorials/bson-v4.txt000066400000000000000000000746461423026727100205550ustar00rootroot00000000000000.. http://docs.mongodb.com/ecosystem/tutorial/ruby-bson-tutorial-4-0/ .. _ruby-bson-tutorial-4-0: ***************** BSON 4.x Tutorial ***************** .. default-domain:: mongodb .. contents:: On this page :local: :backlinks: none :depth: 2 :class: twocols This tutorial discusses using the Ruby BSON library. Installation ============ The BSON library can be installed from `Rubygems `_ manually or with bundler. To install the gem manually: .. code-block:: sh gem install bson -v '~> 4.0' To install the gem with bundler, include the following in your ``Gemfile``: .. code-block:: ruby gem 'bson', '~> 4.0' The BSON library is compatible with MRI >= 2.5 and JRuby >= 9.2. Use With ActiveSupport ====================== Serialization for ActiveSupport-defined classes, such as TimeWithZone, is not loaded by default to avoid a hard dependency of BSON on ActiveSupport. When using BSON in an application that also uses ActiveSupport, the ActiveSupport-related code must be explicitly required: .. code-block:: ruby require 'bson' require 'bson/active_support' BSON Serialization ================== Getting a Ruby object's raw BSON representation is done by calling ``to_bson`` on the Ruby object, which will return a ``BSON::ByteBuffer``. For example: .. code-block:: ruby "Shall I compare thee to a summer's day".to_bson 1024.to_bson Generating an object from BSON is done via calling ``from_bson`` on the class you wish to instantiate and passing it a ``BSON::ByteBuffer`` instance. .. code-block:: ruby String.from_bson(byte_buffer) BSON::Int32.from_bson(byte_buffer) Byte Buffers ============ BSON library 4.0 introduces the use of native byte buffers in MRI and JRuby instead of using ``StringIO``, for improved performance. Writing ------- To create a ``ByteBuffer`` for writing (i.e. serializing to BSON), instantiate ``BSON::ByteBuffer`` with no arguments: .. code-block:: ruby buffer = BSON::ByteBuffer.new To write raw bytes to the byte buffer with no transformations, use ``put_byte`` and ``put_bytes`` methods. They take a byte string as the argument and copy this string into the buffer. ``put_byte`` enforces that the argument is a string of length 1; ``put_bytes`` accepts any length strings. The strings can contain null bytes. .. code-block:: ruby buffer.put_byte("\x00") buffer.put_bytes("\xff\xfe\x00\xfd") .. note:: ``put_byte`` and ``put_bytes`` do not write a BSON type byte prior to writing the argument to the byte buffer. Subsequent write methods write objects of particular types in the `BSON spec `_. Note that the type indicated by the method name takes precedence over the type of the argument - for example, if a floating-point value is given to ``put_int32``, it is coerced into an integer and the resulting integer is written to the byte buffer. To write a UTF-8 string (BSON type 0x02) to the byte buffer, use ``put_string``: .. code-block:: ruby buffer.put_string("hello, world") Note that BSON strings are always encoded in UTF-8. Therefore, the argument must be either in UTF-8 or in an encoding convertable to UTF-8 (i.e. not binary). If the argument is in an encoding other than UTF-8, the string is first converted to UTF-8 and the UTF-8 encoded version is written to the buffer. The string must be valid in its claimed encoding, including being valid UTF-8 if the encoding is UTF-8. The string may contain null bytes. The BSON specification also defines a CString type, which is used for example for document keys. To write CStrings to the buffer, use ``put_cstring``: .. code-block:: ruby buffer.put_cstring("hello, world") As with regular strings, CStrings in BSON must be UTF-8 encoded. If the argument is not in UTF-8, it is converted to UTF-8 and the resulting string is written to the buffer. Unlike ``put_string``, the UTF-8 encoding of the argument given to ``put_cstring`` cannot have any null bytes, since the CString serialization format in BSON is null terminated. Unlike ``put_string``, ``put_cstring`` also accepts symbols and integers. In all cases the argument is stringified prior to being written: .. code-block:: ruby buffer.put_cstring(:hello) buffer.put_cstring(42) To write a 32-bit or a 64-bit integer to the byte buffer, use ``put_int32`` and ``put_int64`` methods respectively. Note that Ruby integers can be arbitrarily large; if the value being written exceeds the range of a 32-bit or a 64-bit integer, ``put_int32`` and ``put_int64`` raise ``RangeError``. .. code-block:: ruby buffer.put_int32(12345) buffer.put_int64(123456789012345) .. note:: If ``put_int32`` or ``put_int64`` are given floating point arguments, the arguments are first coerced into integers and the integers are written to the byte buffer. To write a 64-bit floating point value to the byte buffer, use ``put_double``: .. code-block:: ruby buffer.put_double(3.14159) To obtain the serialized data as a byte string (for example, to send the data over a socket), call ``to_s`` on the buffer: .. code-block:: ruby buffer = BSON::ByteBuffer.new buffer.put_string('testing') socket.write(buffer.to_s) .. note:: ``ByteBuffer`` keeps track of read and write positions separately. There is no way to rewind the buffer for writing - ``rewind`` only affects the read position. Reading ------- To create a ``ByteBuffer`` for reading (i.e. deserializing from BSON), instantiate ``BSON::ByteBuffer`` with a byte string as the argument: .. code-block:: ruby buffer = BSON::ByteBuffer.new(string) # a read mode buffer. Reading from the buffer is done via the following API: .. code-block:: ruby buffer.get_byte # Pulls a single byte from the buffer. buffer.get_bytes(value) # Pulls n number of bytes from the buffer. buffer.get_cstring # Pulls a null-terminated string from the buffer. buffer.get_double # Pulls a 64-bit floating point from the buffer. buffer.get_int32 # Pulls a 32-bit integer (4 bytes) from the buffer. buffer.get_int64 # Pulls a 64-bit integer (8 bytes) from the buffer. buffer.get_string # Pulls a UTF-8 string from the buffer. To restart reading from the beginning of a buffer, use ``rewind``: .. code-block:: ruby buffer.rewind .. note:: ``ByteBuffer`` keeps track of read and write positions separately. ``rewind`` only affects the read position. Supported Classes ================= Core Ruby classes that have representations in the BSON specification and will have a ``to_bson`` method defined for them are: ``Object``, ``Array``, ``FalseClass``, ``Float``, ``Hash``, ``Integer``, ``BigDecimal``, ``NilClass``, ``Regexp``, ``String``, ``Symbol`` (deprecated), ``Time``, ``TrueClass``. In addition to the core Ruby objects, BSON also provides some special types specific to the specification: ``BSON::Binary`` ---------------- Use ``BSON::Binary`` objects to store arbitrary binary data. The ``Binary`` objects can be constructed from binary strings as follows: .. code-block:: ruby BSON::Binary.new("binary_string") # => By default, ``Binary`` objects are created with BSON binary subtype 0 (``:generic``). The subtype can be explicitly specified to indicate that the bytes encode a particular type of data: .. code-block:: ruby BSON::Binary.new("binary_string", :user) # => Valid subtypes are ``:generic``, ``:function``, ``:old``, ``:uuid_old``, ``:uuid``, ``:md5`` and ``:user``. The data and the subtype can be retrieved from ``Binary`` instances using ``data`` and ``type`` attributes, as follows: .. code-block:: ruby binary = BSON::Binary.new("binary_string", :user) binary.data => "binary_string" binary.type => :user .. note:: ``BSON::Binary`` objects always store the data in ``BINARY`` encoding, regardless of the encoding that the string passed to the constructor was in: .. code-block:: ruby str = "binary_string" str.encoding # => # binary = BSON::Binary.new(str) binary.data # => "binary_string" binary.data.encoding # => # UUID Methods ```````````` To create a UUID BSON::Binary (binary subtype 4) from its RFC 4122-compliant string representation, use the ``from_uuid`` method: .. code-block:: ruby uuid_str = "00112233-4455-6677-8899-aabbccddeeff" BSON::Binary.from_uuid(uuid_str) # => To stringify a UUID BSON::Binary to an RFC 4122-compliant representation, use the ``to_uuid`` method: .. code-block:: ruby binary = BSON::Binary.new("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF".force_encoding('BINARY'), :uuid) => binary.to_uuid => "00112233-4455-6677-8899aabbccddeeff" The standard representation may be explicitly specified when invoking both ``from_uuid`` and ``to_uuid`` methods: .. code-block:: ruby binary = BSON::Binary.from_uuid(uuid_str, :standard) binary.to_uuid(:standard) Note that the ``:standard`` representation can only be used with a Binary of subtype ``:uuid`` (not ``:uuid_old``). Legacy UUIDs ```````````` Data stored in BSON::Binary objects of subtype 3 (``:uuid_old``) may be persisted in one of three different byte orders depending on which driver created the data. The byte orders are CSharp legacy, Java legacy and Python legacy. The Python legacy byte order is the same as the standard RFC 4122 byte order; CSharp legacy and Java legacy byte orders have some of the bytes swapped. The Binary object containing a legacy UUID does not encode *which* format the UUID is stored in. Therefore, methods that convert to and from the legacy UUID format take the desired format, or representation, as their argument. An application may copy legacy UUID Binary objects without knowing which byte order they store their data in. The following methods for working with legacy UUIDs are provided for interoperability with existing deployments storing data in legacy UUID formats. It is recommended that new applications use the ``:uuid`` (subtype 4) format only, which is compliant with RFC 4122. To stringify a legacy UUID BSON::Binary, use the ``to_uuid`` method specifying the desired representation. Accepted representations are ``:csharp_legacy``, ``:java_legacy`` and ``:python_legacy``. Note that a legacy UUID BSON::Binary cannot be stringified without specifying a representation. .. code-block:: ruby binary = BSON::Binary.new("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF".force_encoding('BINARY'), :uuid_old) => binary.to_uuid # => ArgumentError (Representation must be specified for BSON::Binary objects of type :uuid_old) binary.to_uuid(:csharp_legacy) # => "33221100-5544-7766-8899aabbccddeeff" binary.to_uuid(:java_legacy) # => "77665544-3322-1100-ffeeddccbbaa9988" binary.to_uuid(:python_legacy) # => "00112233-4455-6677-8899aabbccddeeff" To create a legacy UUID BSON::Binary from the string representation of the UUID, use the ``from_uuid`` method specifying the desired representation: .. code-block:: ruby uuid_str = "00112233-4455-6677-8899-aabbccddeeff" BSON::Binary.from_uuid(uuid_str, :csharp_legacy) # => BSON::Binary.from_uuid(uuid_str, :java_legacy) # => BSON::Binary.from_uuid(uuid_str, :python_legacy) # => These methods can be used to convert from one representation to another: .. code-block:: ruby BSON::Binary.from_uuid('77665544-3322-1100-ffeeddccbbaa9988',:java_legacy).to_uuid(:csharp_legacy) # => "33221100-5544-7766-8899aabbccddeeff" ``BSON::Code`` -------------- Represents a string of JavaScript code. .. code-block:: ruby BSON::Code.new("this.value = 5;") ``BSON::CodeWithScope`` ----------------------- .. note:: The ``CodeWithScope`` type is deprecated as of MongoDB 4.2.1. Starting with MongoDB 4.4, support from ``CodeWithScope`` is being removed from various server commands and operators such as ``$where``. Please use other BSON types and operators when working with MongoDB 4.4 and newer. Represents a string of JavaScript code with a hash of values. .. code-block:: ruby BSON::CodeWithScope.new("this.value = age;", age: 5) ``BSON::DBRef`` --------------- This is a subclass of ``BSON::Document`` that provides accessors for the collection, id, and database of the DBRef. .. code-block:: ruby BSON::DBRef.new({"$ref" => "collection", "$id" => "id"}) BSON::DBRef.new({"$ref" => "collection", "$id" => "id", "database" => "db"}) .. note:: The BSON::DBRef constructor will validate the given hash and will raise an ArgumentError if it is not a valid DBRef. ``BSON::ExtJSON.parse_obj`` and ``Hash.from_bson`` will not raise an error if given an invalid DBRef, and will parse a Hash or deserialize a BSON::Document instead. .. note:: All BSON documents are deserialized into instances of BSON::DBRef if they are valid DBRefs, otherwise they are deserialized into instances of BSON::Document. This is true even when the invocation is made from the ``Hash`` class: .. code-block:: ruby bson = {"$ref" => "collection", "$id" => "id"}.to_bson.to_s loaded = Hash.from_bson(BSON::ByteBuffer.new(bson)) => {"$ref"=>"collection", "$id"=>"id"} loaded.class => BSON::DBRef For backwards compatibility with the MongoDB Ruby driver versions 2.17 and earlier, ``BSON::DBRef`` also can be constructed using the legacy driver API. This API is deprecated and will be removed in a future version of ``bson-ruby``: .. code-block:: ruby BSON::DBRef.new("collection", BSON::ObjectId('61eeb760a15d5d0f9f1e401d')) BSON::DBRef.new("collection", BSON::ObjectId('61eeb760a15d5d0f9f1e401d'), "db") ``BSON::Document`` ------------------ This is a subclass of ``Hash`` that stores all keys as strings, but allows access to them with symbol keys. .. code-block:: ruby BSON::Document[:key, "value"] BSON::Document.new .. note:: All BSON documents are deserialized into instances of BSON::Document (or BSON::DBRef, if they happen to be a valid DBRef), even when the invocation is made from the ``Hash`` class: .. code-block:: ruby bson = {test: 1}.to_bson.to_s loaded = Hash.from_bson(BSON::ByteBuffer.new(bson)) => {"test"=>1} loaded.class => BSON::Document ``BSON::MaxKey`` ---------------- Represents a value in BSON that will always compare higher to another value. .. code-block:: ruby BSON::MaxKey.new ``BSON::MinKey`` ---------------- Represents a value in BSON that will always compare lower to another value. .. code-block:: ruby BSON::MinKey.new ``BSON::ObjectId`` ------------------ Represents a 12 byte unique identifier for an object on a given machine. .. code-block:: ruby BSON::ObjectId.new ``BSON::Timestamp`` ------------------- Represents a special time with a start and increment value. .. code-block:: ruby BSON::Timestamp.new(5, 30) ``BSON::Undefined`` ------------------- Represents a placeholder for a value that was not provided. .. code-block:: ruby BSON::Undefined.new ``BSON::Decimal128`` -------------------- Represents a 128-bit decimal-based floating-point value capable of emulating decimal rounding with exact precision. .. code-block:: ruby # Instantiate with a String BSON::Decimal128.new("1.28") # Instantiate with a BigDecimal d = BigDecimal(1.28, 3) BSON::Decimal128.new(d) BSON::Decimal128 vs BigDecimal `````````````````````````````` The ``BigDecimal`` ``from_bson`` and ``to_bson`` methods use the same ``BSON::Decimal128`` methods under the hood. This leads to some limitations that are imposed on the ``BigDecimal`` values that can be serialized to BSON and those that can be deserialized from existing ``decimal128`` BSON values. This change was made because serializing ``BigDecimal`` instances as ``BSON::Decimal128`` instances allows for more flexibility in terms of querying and aggregation in MongoDB. The limitations imposed on ``BigDecimal`` are as follows: - ``decimal128`` has a limited range and precision, while ``BigDecimal`` has no restrictions in terms of range and precision. ``decimal128`` has a max value of approximately ``10^6145`` and a min value of approximately ``-10^6145``, and has a maximum of 34 bits of precision. - ``decimal128`` is able to accept signed ``NaN`` values, while ``BigDecimal`` is not. All signed ``NaN`` values that are deserialized into ``BigDecimal`` instances will be unsigned. - ``decimal128`` maintains trailing zeroes when serializing to and deserializing from BSON. ``BigDecimal``, however, does not maintain trailing zeroes and therefore using ``BigDecimal`` may result in a lack of precision. .. note:: In BSON 5.0, ``decimal128`` will be deserialized into ``BigDecimal`` by default. In order to have ``decimal128`` values in BSON documents deserialized into ``BSON::Decimal128``, the ``mode: :bson`` option can be set on ``from_bson``. ``Symbol`` ---------- The BSON specification defines a symbol type which allows round-tripping Ruby ``Symbol`` values (i.e., a Ruby ``Symbol``is encoded into a BSON symbol and a BSON symbol is decoded into a Ruby ``Symbol``). However, since most programming langauges do not have a native symbol type, to promote interoperabilty, MongoDB deprecated the BSON symbol type and encourages strings to be used instead. .. note:: In BSON, hash *keys* are always strings. Non-string values will be stringified when used as hash keys: .. code-block:: ruby Hash.from_bson({foo: 'bar'}.to_bson) # => {"foo"=>"bar"} Hash.from_bson({1 => 2}.to_bson) # => {"1"=>2} By default, the BSON library encodes ``Symbol`` hash values as strings and decodes BSON symbols into Ruby ``Symbol`` values: .. code-block:: ruby {foo: :bar}.to_bson.to_s # => "\x12\x00\x00\x00\x02foo\x00\x04\x00\x00\x00bar\x00\x00" # 0x02 is the string type Hash.from_bson(BSON::ByteBuffer.new("\x12\x00\x00\x00\x02foo\x00\x04\x00\x00\x00bar\x00\x00".force_encoding('BINARY'))) # => {"foo"=>"bar"} # 0x0E is the symbol type Hash.from_bson(BSON::ByteBuffer.new("\x12\x00\x00\x00\x0Efoo\x00\x04\x00\x00\x00bar\x00\x00".force_encoding('BINARY'))) # => {"foo"=>:bar} To force encoding of Ruby symbols to BSON symbols, wrap the Ruby symbols in ``BSON::Symbol::Raw``: .. code-block:: ruby {foo: BSON::Symbol::Raw.new(:bar)}.to_bson.to_s # => "\x12\x00\x00\x00\x0Efoo\x00\x04\x00\x00\x00bar\x00\x00" JSON Serialization ================== Some BSON types have special representations in JSON. These are as follows and will be automatically serialized in the form when calling ``to_json`` on them. .. list-table:: :header-rows: 1 :widths: 40 105 * - Object - JSON * - ``BSON::Binary`` - ``{ "$binary" : "\x01", "$type" : "md5" }`` * - ``BSON::Code`` - ``{ "$code" : "this.v = 5" }`` * - ``BSON::CodeWithScope`` - ``{ "$code" : "this.v = value", "$scope" : { v => 5 }}`` * - ``BSON::DBRef`` - ``{ "$ref" : "collection", "$id" : { "$oid" : "id" }, "$db" : "database" }`` * - ``BSON::MaxKey`` - ``{ "$maxKey" : 1 }`` * - ``BSON::MinKey`` - ``{ "$minKey" : 1 }`` * - ``BSON::ObjectId`` - ``{ "$oid" : "4e4d66343b39b68407000001" }`` * - ``BSON::Timestamp`` - ``{ "t" : 5, "i" : 30 }`` * - ``Regexp`` - ``{ "$regex" : "[abc]", "$options" : "i" }`` Time Instances ============== Times in Ruby can have nanosecond precision. Times in BSON (and MongoDB) can only have millisecond precision. When Ruby ``Time`` instances are serialized to BSON or Extended JSON, the times are floored to the nearest millisecond. .. note:: The time as always rounded down. If the time precedes the Unix epoch (January 1, 1970 00:00:00 UTC), the absolute value of the time would increase: .. code-block:: ruby time = Time.utc(1960, 1, 1, 0, 0, 0, 999_999) time.to_f # => -315619199.000001 time.floor(3).to_f # => -315619199.001 .. note:: JRuby as of version 9.2.11.0 `rounds pre-Unix epoch times up rather than down `_. bson-ruby works around this and correctly floors the times when serializing on JRuby. Because of this flooring, applications are strongly recommended to perform all time calculations using integer math, as inexactness of floating point calculations may produce unexpected results. DateTime Instances ================== BSON only supports storing the time as the number of seconds since the Unix epoch. Ruby's ``DateTime`` instances can be serialized to BSON, but when the BSON is deserialized the times will be returned as ``Time`` instances. ``DateTime`` class in Ruby supports non-Gregorian calendars. When non-Gregorian ``DateTime`` instances are serialized, they are first converted to Gregorian calendar, and the respective date in the Gregorian calendar is stored in the database. Date Instances ============== BSON only supports storing the time as the number of seconds since the Unix epoch. Ruby's ``Date`` instances can be serialized to BSON, but when the BSON is deserialized the times will be returned as ``Time`` instances. When ``Date`` instances are serialized, the time value used is midnight of the day that the ``Date`` refers to in UTC. Regular Expressions =================== Both MongoDB and Ruby provide facilities for working with regular expressions, but they use regular expression engines. The following subsections detail the differences between Ruby regular expressions and MongoDB regular expressions and describe how to work with both. Ruby vs MongoDB Regular Expressions ----------------------------------- MongoDB server uses `Perl-compatible regular expressions implemented using the PCRE library `_ and `Ruby regular expressions `_ are implemented using the `Onigmo regular expression engine `_, which is a fork of `Oniguruma `_. The two regular expression implementations generally provide equivalent functionality but have several important syntax differences, as described below. Unfortunately, there is no simple way to programmatically convert a PCRE regular expression into the equivalent Ruby regular expression, and there are currently no Ruby bindings for PCRE. Options / Flags / Modifiers ``````````````````````````` Both Ruby and PCRE regular expressions support modifiers. These are also called "options" in Ruby parlance and "flags" in PCRE parlance. The meaning of ``s`` and ``m`` modifiers differs in Ruby and PCRE: - Ruby does not have the ``s`` modifier, instead the Ruby ``m`` modifier performs the same function as the PCRE ``s`` modifier which is to make the period (``.``) match any character including newlines. Confusingly, the Ruby documentation refers to the ``m`` modifier as "enabling multi-line mode". - Ruby always operates in the equivalent of PCRE's multi-line mode, enabled by the ``m`` modifier in PCRE regular expressions. In Ruby the ``^`` anchor always refers to the beginning of line and the ``$`` anchor always refers to the end of line. When writing regular expressions intended to be used in both Ruby and PCRE environments (including MongoDB server and most other MongoDB drivers), henceforth referred to as "portable regular expressions", avoid using the ``^`` and ``$`` anchors. The following sections provide workarounds and recommendations for authoring portable regular expressions. ``^`` Anchor ```````````` In Ruby regular expressions, the ``^`` anchor always refers to the beginning of line. In PCRE regular expressions, the ``^`` anchor refers to the beginning of input by default and the ``m`` flag changes its meaning to the beginning of line. Both Ruby and PCRE regular expressions support the ``\A`` anchor to refer to the beginning of input, regardless of modifiers. When writing portable regular expressions: - Use the ``\A`` anchor to refer to the beginning of input. - Use the ``^`` anchor to refer to the beginning of line (this requires setting the ``m`` flag in PCRE regular expressions). Alternatively use one of the following constructs which work regardless of modifiers: - ``(?:\A|(?<=\n))`` (handles LF and CR+LF line ends) - ``(?:\A|(?<=[\r\n]))`` (handles CR, LF and CR+LF line ends) ``$`` Anchor ```````````` In Ruby regular expressions, the ``$`` anchor always refers to the end of line. In PCRE regular expressions, the ``$`` anchor refers to the end of input by default and the ``m`` flag changes its meaning to the end of line. Both Ruby and PCRE regular expressions support the ``\z`` anchor to refer to the end of input, regardless of modifiers. When writing portable regular expressions: - Use the ``\z`` anchor to refer to the end of input. - Use the ``$`` anchor to refer to the beginning of line (this requires setting the ``m`` flag in PCRE regular expressions). Alternatively use one of the following constructs which work regardless of modifiers: - ``(?:\z|(?=\n))`` (handles LF and CR+LF line ends) - ``(?:\z|(?=[\n\n]))`` (handles CR, LF and CR+LF line ends) ``BSON::Regexp::Raw`` Class --------------------------- Since there is no simple way to programmatically convert a PCRE regular expression into the equivalent Ruby regular expression, bson-ruby provides the ``BSON::Regexp::Raw`` class for holding MongoDB/PCRE regular expressions. Instances of this class are called "BSON regular expressions" in this documentation. Instances of this class can be created using the regular expression text as a string and optional PCRE modifiers: .. code-block:: ruby BSON::Regexp::Raw.new("^b403158") # => # BSON::Regexp::Raw.new("^Hello.world$", "s") # => # The ``BSON::Regexp`` module is included in the Ruby ``Regexp`` class, such that the ``BSON::`` prefix may be omitted: .. code-block:: ruby Regexp::Raw.new("^b403158") # => # Regexp::Raw.new("^Hello.world$", "s") # => # Regular Expression Conversion ----------------------------- To convert a Ruby regular expression to a BSON regular expression, instantiate a ``BSON::Regexp::Raw`` object as follows: .. code-block:: ruby regexp = /^Hello.world/ bson_regexp = BSON::Regexp::Raw.new(regexp.source, regexp.options) # => # Note that the ``BSON::Regexp::Raw`` constructor accepts both the Ruby numeric options and the PCRE modifier strings. To convert a BSON regular expression to a Ruby regular expression, call the ``compile`` method on the BSON regular expression: .. code-block:: ruby bson_regexp = BSON::Regexp::Raw.new("^hello.world", "s") bson_regexp.compile # => /^hello.world/m bson_regexp = BSON::Regexp::Raw.new("^hello", "") bson_regexp.compile # => /^hello.world/ bson_regexp = BSON::Regexp::Raw.new("^hello.world", "m") bson_regexp.compile # => /^hello.world/ Note that the ``s`` PCRE modifier was converted to the ``m`` Ruby modifier in the first example, and the last two examples were converted to the same regular expression even though the original BSON regular expressions had different meanings. When a BSON regular expression uses the non-portable ``^`` and ``$`` anchors, its conversion to a Ruby regular expression can change its meaning: .. code-block:: ruby BSON::Regexp::Raw.new("^hello.world", "").compile =~ "42\nhello world" # => 3 When a Ruby regular expression is converted to a BSON regular expression (for example, to send to the server as part of a query), the BSON regular expression always has the ``m`` modifier set reflecting the behavior of ``^`` and ``$`` anchors in Ruby regular expressions. Reading and Writing ------------------- Both Ruby and BSON regular expressions implement the ``to_bson`` method for serialization to BSON: .. code-block:: ruby regexp_ruby = /^b403158/ # => /^b403158/ regexp_ruby.to_bson # => # _.to_s # => "^b403158\x00m\x00" regexp_raw = Regexp::Raw.new("^b403158") # => # regexp_raw.to_bson # => # _.to_s # => "^b403158\x00\x00" Both ``Regexp`` and ``BSON::Regexp::Raw`` classes implement the ``from_bson`` class method that deserializes a regular expression from a BSON byte buffer. Methods of both classes return a ``BSON::Regexp::Raw`` instance that must be converted to a Ruby regular expression using the ``compile`` method as described above. .. code-block:: ruby byte_buffer = BSON::ByteBuffer.new("^b403158\x00\x00") regex = Regexp.from_bson(byte_buffer) # => # regex.pattern # => "^b403158" regex.options # => "" regex.compile # => /^b403158/ Key Order ========= BSON documents preserve the order of keys, because the documents are stored as lists of key-value pairs. Hashes in Ruby also preserve key order; thus the order of keys specified in Ruby will be respected when serializing a hash to a BSON document, and when deserializing a BSON document into a hash the order of keys in the document will match the order of keys in the hash. Duplicate Keys ============== BSON specification allows BSON documents to have duplicate keys, because the documents are stored as lists of key-value pairs. Applications should refrain from generating such documents, because MongoDB server behavior is undefined when a BSON document contains duplicate keys. Since in Ruby hashes cannot have duplicate keys, when serializing Ruby hashes to BSON documents no duplicate keys will be generated. (It is still possible to hand-craft a BSON document that would have duplicate keys in Ruby, and some of the other MongoDB BSON libraries may permit creating BSON documents with duplicate keys.) Note that, since keys in BSON documents are always stored as strings, specifying the same key as as string and a symbol in Ruby only retains the most recent specification: .. code-block:: ruby BSON::Document.new(test: 1, 'test' => 2) => {"test"=>2} When loading a BSON document with duplicate keys, the last value for a duplicated key overwrites previous values for the same key. bson-ruby-4.15.0/ext/000077500000000000000000000000001423026727100143255ustar00rootroot00000000000000bson-ruby-4.15.0/ext/bson/000077500000000000000000000000001423026727100152665ustar00rootroot00000000000000bson-ruby-4.15.0/ext/bson/bson-endian.h000066400000000000000000000077051423026727100176450ustar00rootroot00000000000000/* * Copyright (C) 2015-2020 MongoDB Inc. * * 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. */ #if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) # define __WINDOWS__ # include #else # include # include #endif #define BSON_BIG_ENDIAN 4321 #define BSON_LITTLE_ENDIAN 1234 #if defined(__sun) # include # if defined(_LITTLE_ENDIAN) # define BSON_BYTE_ORDER 1234 # else # define BSON_BYTE_ORDER 4321 # endif #endif /* See a similar check in ruby's sha2.h */ # ifndef BSON_BYTE_ORDER # ifdef WORDS_BIGENDIAN # define BSON_BYTE_ORDER BSON_BIG_ENDIAN # else # define BSON_BYTE_ORDER BSON_LITTLE_ENDIAN # endif # endif /* BSON_BYTE_ORDER */ #if defined(__sun) # define BSON_UINT16_SWAP_LE_BE(v) __bson_uint16_swap_slow((uint16_t)v) # define BSON_UINT32_SWAP_LE_BE(v) __bson_uint32_swap_slow((uint32_t)v) # define BSON_UINT64_SWAP_LE_BE(v) __bson_uint64_swap_slow((uint64_t)v) #elif defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) && \ (__clang_major__ >= 3) && (__clang_minor__ >= 1) # if __has_builtin(__builtin_bswap16) # define BSON_UINT16_SWAP_LE_BE(v) __builtin_bswap16(v) # endif # if __has_builtin(__builtin_bswap32) # define BSON_UINT32_SWAP_LE_BE(v) __builtin_bswap32(v) # endif # if __has_builtin(__builtin_bswap64) # define BSON_UINT64_SWAP_LE_BE(v) __builtin_bswap64(v) # endif #elif defined(__GNUC__) && (__GNUC__ >= 4) # if __GNUC__ > 4 || (defined (__GNUC_MINOR__) && __GNUC_MINOR__ >= 3) # define BSON_UINT32_SWAP_LE_BE(v) __builtin_bswap32 ((uint32_t)v) # define BSON_UINT64_SWAP_LE_BE(v) __builtin_bswap64 ((uint64_t)v) # endif #endif #ifndef BSON_UINT16_SWAP_LE_BE # define BSON_UINT16_SWAP_LE_BE(v) __bson_uint16_swap_slow((uint16_t)v) #endif #ifndef BSON_UINT32_SWAP_LE_BE # define BSON_UINT32_SWAP_LE_BE(v) __bson_uint32_swap_slow((uint32_t)v) #endif #ifndef BSON_UINT64_SWAP_LE_BE # define BSON_UINT64_SWAP_LE_BE(v) __bson_uint64_swap_slow((uint64_t)v) #endif #if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN # define BSON_UINT16_TO_BE(v) BSON_UINT16_SWAP_LE_BE(v) # define BSON_UINT32_FROM_LE(v) ((uint32_t)v) # define BSON_UINT32_TO_LE(v) ((uint32_t)v) # define BSON_UINT32_FROM_BE(v) BSON_UINT32_SWAP_LE_BE(v) # define BSON_UINT32_TO_BE(v) BSON_UINT32_SWAP_LE_BE(v) # define BSON_UINT64_FROM_LE(v) ((uint64_t)v) # define BSON_UINT64_TO_LE(v) ((uint64_t)v) # define BSON_UINT64_FROM_BE(v) BSON_UINT64_SWAP_LE_BE(v) # define BSON_UINT64_TO_BE(v) BSON_UINT64_SWAP_LE_BE(v) # define BSON_DOUBLE_FROM_LE(v) ((double)v) # define BSON_DOUBLE_TO_LE(v) ((double)v) #elif BSON_BYTE_ORDER == BSON_BIG_ENDIAN # define BSON_UINT16_TO_BE(v) ((uint16_t)v) # define BSON_UINT32_FROM_LE(v) BSON_UINT32_SWAP_LE_BE(v) # define BSON_UINT32_TO_LE(v) BSON_UINT32_SWAP_LE_BE(v) # define BSON_UINT32_FROM_BE(v) ((uint32_t)v) # define BSON_UINT32_TO_BE(v) ((uint32_t)v) # define BSON_UINT64_FROM_LE(v) BSON_UINT64_SWAP_LE_BE(v) # define BSON_UINT64_TO_LE(v) BSON_UINT64_SWAP_LE_BE(v) # define BSON_UINT64_FROM_BE(v) ((uint64_t)v) # define BSON_UINT64_TO_BE(v) ((uint64_t)v) # define BSON_DOUBLE_FROM_LE(v) (__bson_double_swap_slow(v)) # define BSON_DOUBLE_TO_LE(v) (__bson_double_swap_slow(v)) #else # error "The endianness of target architecture is unknown." #endif uint16_t __bson_uint16_swap_slow(uint16_t v); uint32_t __bson_uint32_swap_slow(uint32_t v); uint64_t __bson_uint64_swap_slow(uint64_t v); double __bson_double_swap_slow(double v); bson-ruby-4.15.0/ext/bson/bson-native.h000066400000000000000000000114551423026727100176720ustar00rootroot00000000000000/* * Copyright (C) 2009-2020 MongoDB Inc. * * 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. */ #include #include #include #include #include #include "bson-endian.h" void rb_bson_utf8_validate (const char *utf8, /* IN */ size_t utf8_len, /* IN */ bool allow_null, /* IN */ const char *data_type); /* IN */ #define BSON_BYTE_BUFFER_SIZE 1024 #ifndef HOST_NAME_HASH_MAX #define HOST_NAME_HASH_MAX 256 #endif /* See the type list in http://bsonspec.org/spec.html. */ #define BSON_TYPE_DOUBLE 1 #define BSON_TYPE_STRING 2 #define BSON_TYPE_DOCUMENT 3 #define BSON_TYPE_ARRAY 4 #define BSON_TYPE_BOOLEAN 8 #define BSON_TYPE_SYMBOL 0x0E #define BSON_TYPE_INT32 0x10 #define BSON_TYPE_INT64 0x12 typedef struct { size_t size; size_t write_position; size_t read_position; char buffer[BSON_BYTE_BUFFER_SIZE]; char *b_ptr; } byte_buffer_t; #define READ_PTR(byte_buffer_ptr) \ (byte_buffer_ptr->b_ptr + byte_buffer_ptr->read_position) #define READ_SIZE(byte_buffer_ptr) \ (byte_buffer_ptr->write_position - byte_buffer_ptr->read_position) #define WRITE_PTR(byte_buffer_ptr) \ (byte_buffer_ptr->b_ptr + byte_buffer_ptr->write_position) #define ENSURE_BSON_WRITE(buffer_ptr, length) \ { if (buffer_ptr->write_position + length > buffer_ptr->size) rb_bson_expand_buffer(buffer_ptr, length); } #define ENSURE_BSON_READ(buffer_ptr, length) \ { if (buffer_ptr->read_position + length > buffer_ptr->write_position) \ rb_raise(rb_eRangeError, "Attempted to read %zu bytes, but only %zu bytes remain", (size_t)length, READ_SIZE(buffer_ptr)); } VALUE rb_bson_byte_buffer_allocate(VALUE klass); VALUE rb_bson_byte_buffer_initialize(int argc, VALUE *argv, VALUE self); VALUE rb_bson_byte_buffer_length(VALUE self); VALUE rb_bson_byte_buffer_get_byte(VALUE self); VALUE rb_bson_byte_buffer_get_bytes(VALUE self, VALUE i); VALUE rb_bson_byte_buffer_get_cstring(VALUE self); VALUE rb_bson_byte_buffer_get_decimal128_bytes(VALUE self); VALUE rb_bson_byte_buffer_get_double(VALUE self); VALUE rb_bson_byte_buffer_get_int32(VALUE self); VALUE rb_bson_byte_buffer_get_uint32(VALUE self); VALUE rb_bson_byte_buffer_get_int64(VALUE self); VALUE rb_bson_byte_buffer_get_string(VALUE self); VALUE rb_bson_byte_buffer_get_hash(int argc, VALUE *argv, VALUE self); VALUE rb_bson_byte_buffer_get_array(int argc, VALUE *argv, VALUE self); VALUE rb_bson_byte_buffer_put_byte(VALUE self, VALUE byte); VALUE rb_bson_byte_buffer_put_bytes(VALUE self, VALUE bytes); VALUE rb_bson_byte_buffer_put_cstring(VALUE self, VALUE string); VALUE rb_bson_byte_buffer_put_decimal128(VALUE self, VALUE low, VALUE high); VALUE rb_bson_byte_buffer_put_double(VALUE self, VALUE f); VALUE rb_bson_byte_buffer_put_int32(VALUE self, VALUE i); VALUE rb_bson_byte_buffer_put_uint32(VALUE self, VALUE i); VALUE rb_bson_byte_buffer_put_int64(VALUE self, VALUE i); VALUE rb_bson_byte_buffer_put_string(VALUE self, VALUE string); VALUE rb_bson_byte_buffer_put_symbol(VALUE self, VALUE symbol); VALUE rb_bson_byte_buffer_put_hash(VALUE self, VALUE hash, VALUE validating_keys); VALUE rb_bson_byte_buffer_put_array(VALUE self, VALUE array, VALUE validating_keys); VALUE rb_bson_byte_buffer_read_position(VALUE self); VALUE rb_bson_byte_buffer_replace_int32(VALUE self, VALUE index, VALUE i); VALUE rb_bson_byte_buffer_rewind(VALUE self); VALUE rb_bson_byte_buffer_write_position(VALUE self); VALUE rb_bson_byte_buffer_to_s(VALUE self); VALUE rb_bson_object_id_generator_next(int argc, VALUE* args, VALUE self); size_t rb_bson_byte_buffer_memsize(const void *ptr); void rb_bson_byte_buffer_free(void *ptr); void rb_bson_expand_buffer(byte_buffer_t* buffer_ptr, size_t length); void rb_bson_generate_machine_id(VALUE rb_md5_class, char *rb_bson_machine_id); VALUE pvt_const_get_2(const char *c1, const char *c2); VALUE pvt_const_get_3(const char *c1, const char *c2, const char *c3); #define BSON_MODE_DEFAULT 0 #define BSON_MODE_BSON 1 int pvt_get_mode_option(int argc, VALUE *argv); /** * The counter for incrementing object ids. */ extern uint32_t rb_bson_object_id_counter; extern VALUE rb_bson_registry; extern VALUE rb_bson_illegal_key; extern const rb_data_type_t rb_byte_buffer_data_type; extern VALUE _ref_str, _id_str, _db_str; bson-ruby-4.15.0/ext/bson/bytebuf.c000066400000000000000000000067021423026727100170770ustar00rootroot00000000000000/* * Copyright (C) 2009-2020 MongoDB Inc. * * 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. */ #include "bson-native.h" /** * Allocates a bson byte buffer that wraps a byte_buffer_t. */ VALUE rb_bson_byte_buffer_allocate(VALUE klass) { byte_buffer_t *b; VALUE obj = TypedData_Make_Struct(klass, byte_buffer_t, &rb_byte_buffer_data_type, b); b->b_ptr = b->buffer; b->size = BSON_BYTE_BUFFER_SIZE; return obj; } /** * Initialize a byte buffer. */ VALUE rb_bson_byte_buffer_initialize(int argc, VALUE *argv, VALUE self) { VALUE bytes; rb_scan_args(argc, argv, "01", &bytes); if (!NIL_P(bytes)) { rb_bson_byte_buffer_put_bytes(self, bytes); } return self; } /** * Expand the byte buffer linearly. */ void rb_bson_expand_buffer(byte_buffer_t* buffer_ptr, size_t length) { const size_t required_size = buffer_ptr->write_position - buffer_ptr->read_position + length; if (required_size <= buffer_ptr->size) { memmove(buffer_ptr->b_ptr, READ_PTR(buffer_ptr), READ_SIZE(buffer_ptr)); buffer_ptr->write_position -= buffer_ptr->read_position; buffer_ptr->read_position = 0; } else { char *new_b_ptr; const size_t new_size = required_size * 2; new_b_ptr = ALLOC_N(char, new_size); memcpy(new_b_ptr, READ_PTR(buffer_ptr), READ_SIZE(buffer_ptr)); if (buffer_ptr->b_ptr != buffer_ptr->buffer) { xfree(buffer_ptr->b_ptr); } buffer_ptr->b_ptr = new_b_ptr; buffer_ptr->size = new_size; buffer_ptr->write_position -= buffer_ptr->read_position; buffer_ptr->read_position = 0; } } /** * Free the memory for the byte buffer. */ void rb_bson_byte_buffer_free(void *ptr) { byte_buffer_t *b = ptr; if (b->b_ptr != b->buffer) { xfree(b->b_ptr); } xfree(b); } /** * Get the length of the buffer. */ VALUE rb_bson_byte_buffer_length(VALUE self) { byte_buffer_t *b; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); return UINT2NUM(READ_SIZE(b)); } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_read_position(VALUE self) { byte_buffer_t *b; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); return INT2NUM(b->read_position); } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_rewind(VALUE self) { byte_buffer_t *b; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); b->read_position = 0; return self; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_write_position(VALUE self) { byte_buffer_t *b; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); return INT2NUM(b->write_position); } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_to_s(VALUE self) { byte_buffer_t *b; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); return rb_str_new(READ_PTR(b), READ_SIZE(b)); } /** * Get the size of the byte_buffer_t in memory. */ size_t rb_bson_byte_buffer_memsize(const void *ptr) { return ptr ? sizeof(byte_buffer_t) : 0; } bson-ruby-4.15.0/ext/bson/endian.c000066400000000000000000000056561423026727100167040ustar00rootroot00000000000000/* * Copyright (C) 2015-2020 MongoDB Inc. * * 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. */ #include #include #include "bson-endian.h" /* *-------------------------------------------------------------------------- * * __bson_uint16_swap_slow -- * * Fallback endianness conversion for 16-bit integers. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ uint16_t __bson_uint16_swap_slow(uint16_t v) { return ((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8); } /* *-------------------------------------------------------------------------- * * __bson_uint32_swap_slow -- * * Fallback endianness conversion for 32-bit integers. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ uint32_t __bson_uint32_swap_slow(uint32_t v) { return ((v & 0x000000FFU) << 24) | ((v & 0x0000FF00U) << 8) | ((v & 0x00FF0000U) >> 8) | ((v & 0xFF000000U) >> 24); } /* *-------------------------------------------------------------------------- * * __bson_uint64_swap_slow -- * * Fallback endianness conversion for 64-bit integers. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ uint64_t __bson_uint64_swap_slow(uint64_t v) { return ((v & 0x00000000000000FFULL) << 56) | ((v & 0x000000000000FF00ULL) << 40) | ((v & 0x0000000000FF0000ULL) << 24) | ((v & 0x00000000FF000000ULL) << 8) | ((v & 0x000000FF00000000ULL) >> 8) | ((v & 0x0000FF0000000000ULL) >> 24) | ((v & 0x00FF000000000000ULL) >> 40) | ((v & 0xFF00000000000000ULL) >> 56); } /* *-------------------------------------------------------------------------- * * __bson_double_swap_slow -- * * Fallback endianness conversion for double floating point. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ double __bson_double_swap_slow(double v) { uint64_t uv; memcpy(&uv, &v, sizeof(v)); uv = BSON_UINT64_SWAP_LE_BE(uv); memcpy(&v, &uv, sizeof(v)); return v; } bson-ruby-4.15.0/ext/bson/extconf.rb000066400000000000000000000001161423026727100172570ustar00rootroot00000000000000require "mkmf" $CFLAGS << " -Wall -g -std=c99" create_makefile("bson_native") bson-ruby-4.15.0/ext/bson/init.c000066400000000000000000000302641423026727100164020ustar00rootroot00000000000000/* * Copyright (C) 2009-2020 MongoDB Inc. * * 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. */ #include "bson-native.h" /** * The counter for incrementing object ids. */ uint32_t rb_bson_object_id_counter; VALUE rb_bson_registry; VALUE rb_bson_illegal_key; const rb_data_type_t rb_byte_buffer_data_type = { "bson/byte_buffer", { NULL, rb_bson_byte_buffer_free, rb_bson_byte_buffer_memsize } }; VALUE _ref_str, _id_str, _db_str; /** * Initialize the bson_native extension. */ void Init_bson_native() { char rb_bson_machine_id[256]; _ref_str = rb_str_new_cstr("$ref"); rb_gc_register_mark_object(_ref_str); _id_str = rb_str_new_cstr("$id"); rb_gc_register_mark_object(_id_str); _db_str = rb_str_new_cstr("$db"); rb_gc_register_mark_object(_db_str); VALUE rb_bson_module = rb_define_module("BSON"); /* Document-class: BSON::ByteBuffer * * Stores BSON-serialized data and provides efficient serialization and * deserialization of common Ruby classes using native code. */ VALUE rb_byte_buffer_class = rb_define_class_under(rb_bson_module, "ByteBuffer", rb_cObject); VALUE rb_bson_object_id_class = rb_const_get(rb_bson_module, rb_intern("ObjectId")); VALUE rb_bson_object_id_generator_class = rb_const_get(rb_bson_object_id_class, rb_intern("Generator")); VALUE rb_digest_class = rb_const_get(rb_cObject, rb_intern("Digest")); VALUE rb_md5_class = rb_const_get(rb_digest_class, rb_intern("MD5")); rb_bson_illegal_key = rb_const_get(rb_const_get(rb_bson_module, rb_intern("String")),rb_intern("IllegalKey")); rb_gc_register_mark_object(rb_bson_illegal_key); rb_define_alloc_func(rb_byte_buffer_class, rb_bson_byte_buffer_allocate); rb_define_method(rb_byte_buffer_class, "initialize", rb_bson_byte_buffer_initialize, -1); /* * call-seq: * buffer.length -> Fixnum * * Returns the number of bytes available to be read in the buffer. * * When a buffer is being written to, each added byte increases its length. * When a buffer is being read from, each read byte decreases its length. */ rb_define_method(rb_byte_buffer_class, "length", rb_bson_byte_buffer_length, 0); /* * call-seq: * buffer.read_position -> Fixnum * * Returns the read position in the buffer. */ rb_define_method(rb_byte_buffer_class, "read_position", rb_bson_byte_buffer_read_position, 0); rb_define_method(rb_byte_buffer_class, "get_byte", rb_bson_byte_buffer_get_byte, 0); rb_define_method(rb_byte_buffer_class, "get_bytes", rb_bson_byte_buffer_get_bytes, 1); rb_define_method(rb_byte_buffer_class, "get_cstring", rb_bson_byte_buffer_get_cstring, 0); rb_define_method(rb_byte_buffer_class, "get_decimal128_bytes", rb_bson_byte_buffer_get_decimal128_bytes, 0); rb_define_method(rb_byte_buffer_class, "get_double", rb_bson_byte_buffer_get_double, 0); /* * call-seq: * buffer.get_hash(**options) -> Hash * * Reads a document from the byte buffer and returns it as a BSON::Document. * * @option options [ nil | :bson ] :mode Decoding mode to use. * * @return [ BSON::Document ] The decoded document. */ rb_define_method(rb_byte_buffer_class, "get_hash", rb_bson_byte_buffer_get_hash, -1); /* * call-seq: * buffer.get_array(**options) -> Array * * Reads an array from the byte buffer. * * @option options [ nil | :bson ] :mode Decoding mode to use. * * @return [ Array ] The decoded array. */ rb_define_method(rb_byte_buffer_class, "get_array", rb_bson_byte_buffer_get_array, -1); rb_define_method(rb_byte_buffer_class, "get_int32", rb_bson_byte_buffer_get_int32, 0); /* * call-seq: * buffer.get_uint32(buffer) -> Fixnum * * Reads an unsigned 32 bit number from the byte buffer. * * @return [ Fixnum ] The unsigned 32 bits integer from the buffer * * @api private */ rb_define_method(rb_byte_buffer_class, "get_uint32", rb_bson_byte_buffer_get_uint32, 0); rb_define_method(rb_byte_buffer_class, "get_int64", rb_bson_byte_buffer_get_int64, 0); rb_define_method(rb_byte_buffer_class, "get_string", rb_bson_byte_buffer_get_string, 0); /* * call-seq: * buffer.write_position -> Fixnum * * Returns the write position in the buffer. */ rb_define_method(rb_byte_buffer_class, "write_position", rb_bson_byte_buffer_write_position, 0); /* * call-seq: * buffer.put_byte(binary_str) -> ByteBuffer * * Writes the specified byte string, which must be of length 1, * to the byte buffer. * * Returns the modified +self+. */ rb_define_method(rb_byte_buffer_class, "put_byte", rb_bson_byte_buffer_put_byte, 1); /* * call-seq: * buffer.put_bytes(binary_str) -> ByteBuffer * * Writes the specified byte string to the byte buffer. * * This method writes exactly the provided byte string - in particular, it * does not prepend the length, and does not append a null byte at the end. * * Returns the modified +self+. */ rb_define_method(rb_byte_buffer_class, "put_bytes", rb_bson_byte_buffer_put_bytes, 1); /* * call-seq: * buffer.put_string(str) -> ByteBuffer * * Writes the specified string to the byte buffer as a BSON string. * * Unlike #put_bytes, this method writes the provided byte string as * a "BSON string" - the string is prefixed with its length and suffixed * with a null byte. The byte string may contain null bytes itself thus * the null terminator is redundant, but it is required by the BSON * specification. * * +str+ must either already be in UTF-8 encoding or be a string encodable * to UTF-8. In particular, a string in BINARY/ASCII-8BIT encoding is * generally not suitable for this method. +EncodingError+ will be raised * if +str+ cannot be encoded in UTF-8, or if +str+ claims to be encoded in * UTF-8 but contains bytes/byte sequences which are not valid in UTF-8. * Use #put_bytes to write arbitrary byte strings to the buffer. * * Returns the modified +self+. */ rb_define_method(rb_byte_buffer_class, "put_string", rb_bson_byte_buffer_put_string, 1); /** * call-seq: * buffer.put_cstring(obj) -> ByteBuffer * * Converts +obj+ to a string, which must not contain any null bytes, and * which must be valid UTF-8, and writes the string to the buffer as a * BSON cstring. +obj+ can be an instance of String, Symbol or Fixnum. * * If the string serialization of +obj+ contains null bytes, this method * raises +ArgumentError+. If +obj+ is of an unsupported type, this method * raises +TypeError+. * * BSON cstring serialization contains no length of the string (relying * instead on the null terminator), unlike the BSON string serialization. */ rb_define_method(rb_byte_buffer_class, "put_cstring", rb_bson_byte_buffer_put_cstring, 1); /** * call-seq: * buffer.put_symbol(sym) -> ByteBuffer * * Converts +sym+ to a string and writes the resulting string to the byte * buffer. * * The symbol may contain null bytes. * * The symbol value is assumed to be encoded in UTF-8. If the symbol value * contains bytes or byte sequences that are not valid in UTF-8, this method * raises +EncodingError+. * * Note: due to the string conversion, a symbol written to the buffer becomes * indistinguishable from a string with the same value written to the buffer. */ rb_define_method(rb_byte_buffer_class, "put_symbol", rb_bson_byte_buffer_put_symbol, 1); /* * call-seq: * buffer.put_int32(fixnum) -> ByteBuffer * * Writes a 32-bit integer value to the buffer. * * If the argument cannot be represented in 32 bits, raises RangeError. * * Returns the modified +self+. */ rb_define_method(rb_byte_buffer_class, "put_int32", rb_bson_byte_buffer_put_int32, 1); /* * call-seq: * buffer.put_uint32(fixnum) -> ByteBuffer * * Writes an unsigned 32-bit integer value to the buffer. * * If the argument cannot be represented in 32 bits, raises RangeError. * * Returns the modified +self+. * * @api private * */ rb_define_method(rb_byte_buffer_class, "put_uint32", rb_bson_byte_buffer_put_uint32, 1); /* * call-seq: * buffer.put_int64(fixnum) -> ByteBuffer * * Writes a 64-bit integer value to the buffer. * * If the argument cannot be represented in 64 bits, raises RangeError. * * Returns the modified +self+. */ rb_define_method(rb_byte_buffer_class, "put_int64", rb_bson_byte_buffer_put_int64, 1); /* * call-seq: * buffer.put_double(double) -> ByteBuffer * * Writes a 64-bit floating point value to the buffer. * * Returns the modified +self+. */ rb_define_method(rb_byte_buffer_class, "put_double", rb_bson_byte_buffer_put_double, 1); /* * call-seq: * buffer.put_decimal128(low_64bit, high_64bit) -> ByteBuffer * * Writes a 128-bit Decimal128 value to the buffer. * * +low_64bit+ and +high_64bit+ are Fixnum objects containing the low and * the high parts of the 128-bit Decimal128 value, respectively. * * Returns the modified +self+. */ rb_define_method(rb_byte_buffer_class, "put_decimal128", rb_bson_byte_buffer_put_decimal128, 2); /* * call-seq: * buffer.put_hash(hash, validating_keys) -> ByteBuffer * * Writes a Hash into the byte buffer. * * Returns the modified +self+. */ rb_define_method(rb_byte_buffer_class, "put_hash", rb_bson_byte_buffer_put_hash, 2); /* * call-seq: * buffer.put_array(array) -> ByteBuffer * * Writes an Array into the byte buffer. * * Returns the modified +self+. */ rb_define_method(rb_byte_buffer_class, "put_array", rb_bson_byte_buffer_put_array, 2); /* * call-seq: * buffer.replace_int32(position, fixnum) -> ByteBuffer * * Replaces a 32-bit integer value at the specified position in the buffer. * * The position must be a non-negative integer, and must be completely * contained within the data already written. For example, if the buffer has * the write position of 12, the acceptable range of positions for this * method is 0..8. * * If the argument cannot be represented in 32 bits, raises RangeError. * * Returns the modified +self+. */ rb_define_method(rb_byte_buffer_class, "replace_int32", rb_bson_byte_buffer_replace_int32, 2); /* * call-seq: * buffer.rewind! -> ByteBuffer * * Resets the read position to the beginning of the byte buffer. * * Note: +rewind!+ does not change the buffer's write position. * * Returns the modified +self+. */ rb_define_method(rb_byte_buffer_class, "rewind!", rb_bson_byte_buffer_rewind, 0); /* * call-seq: * buffer.to_s -> String * * Returns the contents of the buffer as a binary string. * * If the buffer is used for reading, the returned contents is the data * that was not yet read. If the buffer is used for writing, the returned * contents is the complete data that has been written so far. * * Note: this method copies the buffer's contents into a newly allocated * +String+ instance. It does not return a reference to the data stored in * the buffer itself. */ rb_define_method(rb_byte_buffer_class, "to_s", rb_bson_byte_buffer_to_s, 0); rb_define_method(rb_bson_object_id_generator_class, "next_object_id", rb_bson_object_id_generator_next, -1); // Get the object id machine id and hash it. rb_require("digest/md5"); gethostname(rb_bson_machine_id, sizeof(rb_bson_machine_id)); rb_bson_machine_id[255] = '\0'; rb_bson_generate_machine_id(rb_md5_class, rb_bson_machine_id); // Set the object id counter to a random number rb_bson_object_id_counter = FIX2INT(rb_funcall(rb_mKernel, rb_intern("rand"), 1, INT2FIX(0x1000000))); rb_bson_registry = rb_const_get(rb_bson_module, rb_intern("Registry")); rb_gc_register_mark_object(rb_bson_registry); } bson-ruby-4.15.0/ext/bson/libbson-utf8.c000066400000000000000000000145661423026727100177620ustar00rootroot00000000000000#include #include #include #include #include #include "bson-native.h" /** * Taken from libbson. */ #define BSON_ASSERT assert #define BSON_INLINE /* *-------------------------------------------------------------------------- * * _bson_utf8_get_sequence -- * * Determine the sequence length of the first UTF-8 character in * @utf8. The sequence length is stored in @seq_length and the mask * for the first character is stored in @first_mask. * * Returns: * None. * * Side effects: * @seq_length is set. * @first_mask is set. * *-------------------------------------------------------------------------- */ static BSON_INLINE void _bson_utf8_get_sequence (const char *utf8, /* IN */ uint8_t *seq_length, /* OUT */ uint8_t *first_mask) /* OUT */ { unsigned char c = *(const unsigned char *) utf8; uint8_t m; uint8_t n; /* * See the following[1] for a description of what the given multi-byte * sequences will be based on the bits set of the first byte. We also need * to mask the first byte based on that. All subsequent bytes are masked * against 0x3F. * * [1] http://www.joelonsoftware.com/articles/Unicode.html */ if ((c & 0x80) == 0) { n = 1; m = 0x7F; } else if ((c & 0xE0) == 0xC0) { n = 2; m = 0x1F; } else if ((c & 0xF0) == 0xE0) { n = 3; m = 0x0F; } else if ((c & 0xF8) == 0xF0) { n = 4; m = 0x07; } else { n = 0; m = 0; } *seq_length = n; *first_mask = m; } /* *-------------------------------------------------------------------------- * * bson_utf8_validate -- * * Validates that @utf8 is a valid UTF-8 string. Note that we only * support UTF-8 characters which have sequence length less than or equal * to 4 bytes (RFC 3629). * * If @allow_null is true, then \0 is allowed within @utf8_len bytes * of @utf8. Generally, this is bad practice since the main point of * UTF-8 strings is that they can be used with strlen() and friends. * However, some languages such as Python can send UTF-8 encoded * strings with NUL's in them. * * Parameters: * @utf8: A UTF-8 encoded string. * @utf8_len: The length of @utf8 in bytes. * @allow_null: If \0 is allowed within @utf8, exclusing trailing \0. * @data_type: The data type being serialized. * * Returns: * true if @utf8 is valid UTF-8. otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void rb_bson_utf8_validate (const char *utf8, /* IN */ size_t utf8_len, /* IN */ bool allow_null, /* IN */ const char *data_type) /* IN */ { uint32_t c; uint8_t first_mask; uint8_t seq_length; unsigned i; unsigned j; bool not_shortest_form; BSON_ASSERT (utf8); for (i = 0; i < utf8_len; i += seq_length) { _bson_utf8_get_sequence (&utf8[i], &seq_length, &first_mask); /* * Ensure we have a valid multi-byte sequence length. */ if (!seq_length) { rb_raise(rb_eEncodingError, "%s %s is not valid UTF-8: bogus initial bits", data_type, utf8); } /* * Ensure we have enough bytes left. */ if ((utf8_len - i) < seq_length) { rb_raise(rb_eEncodingError, "%s %s is not valid UTF-8: truncated multi-byte sequence", data_type, utf8); } /* * Also calculate the next char as a unichar so we can * check code ranges for non-shortest form. */ c = utf8[i] & first_mask; /* * Check the high-bits for each additional sequence byte. */ for (j = i + 1; j < (i + seq_length); j++) { c = (c << 6) | (utf8[j] & 0x3F); if ((utf8[j] & 0xC0) != 0x80) { rb_raise(rb_eEncodingError, "%s %s is not valid UTF-8: bogus high bits for continuation byte", data_type, utf8); } } /* * Check for NULL bytes afterwards. * * Hint: if you want to optimize this function, starting here to do * this in the same pass as the data above would probably be a good * idea. You would add a branch into the inner loop, but save possibly * on cache-line bouncing on larger strings. Just a thought. */ if (!allow_null) { for (j = 0; j < seq_length; j++) { if (((i + j) > utf8_len) || !utf8[i + j]) { rb_raise(rb_eArgError, "%s %s contains null bytes", data_type, utf8); } } } /* * Code point won't fit in utf-16, not allowed. */ if (c > 0x0010FFFF) { rb_raise(rb_eEncodingError, "%s %s is not valid UTF-8: code point %"PRIu32" does not fit in UTF-16", data_type, utf8, c); } /* * Byte is in reserved range for UTF-16 high-marks * for surrogate pairs. */ if ((c & 0xFFFFF800) == 0xD800) { rb_raise(rb_eEncodingError, "%s %s is not valid UTF-8: byte is in surrogate pair reserved range", data_type, utf8); } /* * Check non-shortest form unicode. */ not_shortest_form = false; switch (seq_length) { case 1: if (c <= 0x007F) { continue; } not_shortest_form = true; case 2: if ((c >= 0x0080) && (c <= 0x07FF)) { continue; } else if (c == 0) { /* Two-byte representation for NULL. */ if (!allow_null) { rb_raise(rb_eArgError, "%s %s contains null bytes", data_type, utf8); } continue; } not_shortest_form = true; case 3: if (((c >= 0x0800) && (c <= 0x0FFF)) || ((c >= 0x1000) && (c <= 0xFFFF))) { continue; } not_shortest_form = true; case 4: if (((c >= 0x10000) && (c <= 0x3FFFF)) || ((c >= 0x40000) && (c <= 0xFFFFF)) || ((c >= 0x100000) && (c <= 0x10FFFF))) { continue; } not_shortest_form = true; default: not_shortest_form = true; } if (not_shortest_form) { rb_raise(rb_eEncodingError, "%s %s is not valid UTF-8: not in shortest form", data_type, utf8); } } } bson-ruby-4.15.0/ext/bson/read.c000066400000000000000000000273511423026727100163550ustar00rootroot00000000000000/* * Copyright (C) 2009-2020 MongoDB Inc. * * 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. */ #include "bson-native.h" #include static void pvt_raise_decode_error(volatile VALUE msg); static int32_t pvt_validate_length(byte_buffer_t *b); static uint8_t pvt_get_type_byte(byte_buffer_t *b); static VALUE pvt_get_int32(byte_buffer_t *b); static VALUE pvt_get_uint32(byte_buffer_t *b); static VALUE pvt_get_int64(byte_buffer_t *b, int argc, VALUE *argv); static VALUE pvt_get_double(byte_buffer_t *b); static VALUE pvt_get_string(byte_buffer_t *b, const char *data_type); static VALUE pvt_get_symbol(byte_buffer_t *b, VALUE rb_buffer, int argc, VALUE *argv); static VALUE pvt_get_boolean(byte_buffer_t *b); static VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type, int argc, VALUE *argv); static void pvt_skip_cstring(byte_buffer_t *b); void pvt_raise_decode_error(volatile VALUE msg) { VALUE klass = pvt_const_get_3("BSON", "Error", "BSONDecodeError"); rb_exc_raise(rb_exc_new_str(klass, msg)); } /** * validate the buffer contains the amount of bytes the array / hash claimns * and that it is null terminated */ int32_t pvt_validate_length(byte_buffer_t *b) { int32_t length; ENSURE_BSON_READ(b, 4); memcpy(&length, READ_PTR(b), 4); length = BSON_UINT32_TO_LE(length); /* minimum valid length is 4 (byte count) + 1 (terminating byte) */ if(length >= 5){ ENSURE_BSON_READ(b, length); /* The last byte should be a null byte: it should be at length - 1 */ if( *(READ_PTR(b) + length - 1) != 0 ){ rb_raise(rb_eRangeError, "Buffer should have contained null terminator at %zu but contained %d", b->read_position + (size_t)length, (int)*(READ_PTR(b) + length)); } b->read_position += 4; } else{ rb_raise(rb_eRangeError, "Buffer contained invalid length %d at %zu", length, b->read_position); } return length; } /** * Read a single field from a hash or array */ VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type, int argc, VALUE *argv) { switch(type) { case BSON_TYPE_INT32: return pvt_get_int32(b); case BSON_TYPE_INT64: return pvt_get_int64(b, argc, argv); case BSON_TYPE_DOUBLE: return pvt_get_double(b); case BSON_TYPE_STRING: return pvt_get_string(b, "String"); case BSON_TYPE_SYMBOL: return pvt_get_symbol(b, rb_buffer, argc, argv); case BSON_TYPE_ARRAY: return rb_bson_byte_buffer_get_array(argc, argv, rb_buffer); case BSON_TYPE_DOCUMENT: return rb_bson_byte_buffer_get_hash(argc, argv, rb_buffer); case BSON_TYPE_BOOLEAN: return pvt_get_boolean(b); default: { VALUE klass = rb_funcall(rb_bson_registry,rb_intern("get"),1, INT2FIX(type)); VALUE value = rb_funcall(klass, rb_intern("from_bson"),1, rb_buffer); RB_GC_GUARD(klass); return value; } } } /** * Get a single byte from the buffer. */ VALUE rb_bson_byte_buffer_get_byte(VALUE self) { byte_buffer_t *b; VALUE byte; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); ENSURE_BSON_READ(b, 1); byte = rb_str_new(READ_PTR(b), 1); b->read_position += 1; return byte; } uint8_t pvt_get_type_byte(byte_buffer_t *b){ int8_t byte; ENSURE_BSON_READ(b, 1); byte = *READ_PTR(b); b->read_position += 1; return (uint8_t)byte; } /** * Get bytes from the buffer. */ VALUE rb_bson_byte_buffer_get_bytes(VALUE self, VALUE i) { byte_buffer_t *b; VALUE bytes; const uint32_t length = FIX2LONG(i); TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); ENSURE_BSON_READ(b, length); bytes = rb_str_new(READ_PTR(b), length); b->read_position += length; return bytes; } VALUE pvt_get_boolean(byte_buffer_t *b){ VALUE result; char byte_value; ENSURE_BSON_READ(b, 1); byte_value = *READ_PTR(b); switch (byte_value) { case 1: result = Qtrue; break; case 0: result = Qfalse; break; default: pvt_raise_decode_error(rb_sprintf("Invalid boolean byte value: %d", (int) byte_value)); } b->read_position += 1; return result; } /** * Get a string from the buffer. */ VALUE rb_bson_byte_buffer_get_string(VALUE self) { byte_buffer_t *b; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); return pvt_get_string(b, "String"); } VALUE pvt_get_string(byte_buffer_t *b, const char *data_type) { int32_t length_le; int32_t length; char *str_ptr; VALUE string; unsigned char last_byte; ENSURE_BSON_READ(b, 4); memcpy(&length_le, READ_PTR(b), 4); length = BSON_UINT32_FROM_LE(length_le); if (length < 0) { pvt_raise_decode_error(rb_sprintf("String length is negative: %d", length)); } if (length == 0) { pvt_raise_decode_error(rb_str_new_cstr("String length is zero but string must be null-terminated")); } ENSURE_BSON_READ(b, 4 + length); str_ptr = READ_PTR(b) + 4; last_byte = *(READ_PTR(b) + 4 + length - 1); if (last_byte != 0) { pvt_raise_decode_error(rb_sprintf("Last byte of the string is not null: 0x%x", (int) last_byte)); } rb_bson_utf8_validate(str_ptr, length - 1, true, data_type); string = rb_enc_str_new(str_ptr, length - 1, rb_utf8_encoding()); b->read_position += 4 + length; return string; } /** * Reads a UTF-8 string out of the byte buffer. If the argc/argv arguments * have a :mode option with the value of :bson, wraps the string in a * BSON::Symbol::Raw. Otherwise consults the BSON registry to determine * which class to instantiate (String in bson-ruby, overridden to Symbol by * the Ruby driver). Returns either a BSON::Symbol::Raw, Symbol or String * value. */ VALUE pvt_get_symbol(byte_buffer_t *b, VALUE rb_buffer, int argc, VALUE *argv) { VALUE value, klass; if (pvt_get_mode_option(argc, argv) == BSON_MODE_BSON) { value = pvt_get_string(b, "Symbol"); klass = pvt_const_get_3("BSON", "Symbol", "Raw"); value = rb_funcall(klass, rb_intern("new"), 1, value); } else { klass = rb_funcall(rb_bson_registry, rb_intern("get"), 1, INT2FIX(BSON_TYPE_SYMBOL)); value = rb_funcall(klass, rb_intern("from_bson"), 1, rb_buffer); } RB_GC_GUARD(klass); return value; } /** * Get a cstring from the buffer. */ VALUE rb_bson_byte_buffer_get_cstring(VALUE self) { byte_buffer_t *b; VALUE string; int length; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); length = (int)strlen(READ_PTR(b)); ENSURE_BSON_READ(b, length); string = rb_enc_str_new(READ_PTR(b), length, rb_utf8_encoding()); b->read_position += length + 1; return string; } /** * Reads but does not return a cstring from the buffer. */ void pvt_skip_cstring(byte_buffer_t *b) { int length; length = (int)strlen(READ_PTR(b)); ENSURE_BSON_READ(b, length); b->read_position += length + 1; } /** * Get a int32 from the buffer. */ VALUE rb_bson_byte_buffer_get_int32(VALUE self) { byte_buffer_t *b; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); return pvt_get_int32(b); } VALUE pvt_get_int32(byte_buffer_t *b) { int32_t i32; ENSURE_BSON_READ(b, 4); memcpy(&i32, READ_PTR(b), 4); b->read_position += 4; return INT2NUM(BSON_UINT32_FROM_LE(i32)); } /** * Get an unsigned int32 from the buffer. */ VALUE rb_bson_byte_buffer_get_uint32(VALUE self) { byte_buffer_t *b; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); return pvt_get_uint32(b); } VALUE pvt_get_uint32(byte_buffer_t *b) { uint32_t i32; ENSURE_BSON_READ(b, 4); memcpy(&i32, READ_PTR(b), 4); b->read_position += 4; return UINT2NUM(BSON_UINT32_FROM_LE(i32)); } /** * Get a int64 from the buffer. */ VALUE rb_bson_byte_buffer_get_int64(VALUE self) { byte_buffer_t *b; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); return pvt_get_int64(b, 0, NULL); } /** * Reads a 64-bit integer out of the byte buffer into a Ruby Integer instance. * If the argc/argv arguments have a :mode option with the value of :bson, * wraps the integer in a BSON::Int64. Returns either the Integer or the * BSON::Int64 instance. */ VALUE pvt_get_int64(byte_buffer_t *b, int argc, VALUE *argv) { int64_t i64; VALUE num; ENSURE_BSON_READ(b, 8); memcpy(&i64, READ_PTR(b), 8); b->read_position += 8; num = LL2NUM(BSON_UINT64_FROM_LE(i64)); if (pvt_get_mode_option(argc, argv) == BSON_MODE_BSON) { VALUE klass = rb_funcall(rb_bson_registry,rb_intern("get"),1, INT2FIX(BSON_TYPE_INT64)); VALUE value = rb_funcall(klass, rb_intern("new"), 1, num); RB_GC_GUARD(klass); return value; } else { return num; } RB_GC_GUARD(num); } /** * Get a double from the buffer. */ VALUE rb_bson_byte_buffer_get_double(VALUE self) { byte_buffer_t *b; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); return pvt_get_double(b); } VALUE pvt_get_double(byte_buffer_t *b) { double d; ENSURE_BSON_READ(b, 8); memcpy(&d, READ_PTR(b), 8); b->read_position += 8; return DBL2NUM(BSON_DOUBLE_FROM_LE(d)); } /** * Get the 16 bytes representing the decimal128 from the buffer. */ VALUE rb_bson_byte_buffer_get_decimal128_bytes(VALUE self) { byte_buffer_t *b; VALUE bytes; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); ENSURE_BSON_READ(b, 16); bytes = rb_str_new(READ_PTR(b), 16); b->read_position += 16; return bytes; } /** * This duplicates the DBRef validation code in DBRef constructor. */ static int pvt_is_dbref(VALUE doc) { VALUE ref, id, db; ref = rb_hash_aref(doc, _ref_str); if (NIL_P(ref) || !RB_TYPE_P(ref, T_STRING)) { return 0; } id = rb_hash_aref(doc, _id_str); if (NIL_P(id)) { return 0; } db = rb_hash_aref(doc, _db_str); if (!NIL_P(db) && !RB_TYPE_P(db, T_STRING)) { return 0; } return 1; } VALUE rb_bson_byte_buffer_get_hash(int argc, VALUE *argv, VALUE self){ VALUE doc = Qnil; byte_buffer_t *b = NULL; uint8_t type; VALUE cDocument = pvt_const_get_2("BSON", "Document"); int32_t length; char *start_ptr; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); start_ptr = READ_PTR(b); length = pvt_validate_length(b); doc = rb_funcall(cDocument, rb_intern("allocate"), 0); while((type = pvt_get_type_byte(b)) != 0){ VALUE field = rb_bson_byte_buffer_get_cstring(self); rb_hash_aset(doc, field, pvt_read_field(b, self, type, argc, argv)); RB_GC_GUARD(field); } if (READ_PTR(b) - start_ptr != length) { pvt_raise_decode_error(rb_sprintf("Expected to read %d bytes for the hash but read %ld bytes", length, READ_PTR(b) - start_ptr)); } if (pvt_is_dbref(doc)) { VALUE cDBRef = pvt_const_get_2("BSON", "DBRef"); doc = rb_funcall(cDBRef, rb_intern("new"), 1, doc); } return doc; } VALUE rb_bson_byte_buffer_get_array(int argc, VALUE *argv, VALUE self){ byte_buffer_t *b; VALUE array = Qnil; uint8_t type; int32_t length; char *start_ptr; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); start_ptr = READ_PTR(b); length = pvt_validate_length(b); array = rb_ary_new(); while((type = pvt_get_type_byte(b)) != 0){ pvt_skip_cstring(b); rb_ary_push(array, pvt_read_field(b, self, type, argc, argv)); } RB_GC_GUARD(array); if (READ_PTR(b) - start_ptr != length) { pvt_raise_decode_error(rb_sprintf("Expected to read %d bytes for the hash but read %ld bytes", length, READ_PTR(b) - start_ptr)); } return array; } bson-ruby-4.15.0/ext/bson/util.c000066400000000000000000000055541423026727100164200ustar00rootroot00000000000000/* * Copyright (C) 2009-2020 MongoDB Inc. * * 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. */ #include "bson-native.h" /** * Holds the machine id hash for object id generation. */ static char rb_bson_machine_id_hash[HOST_NAME_HASH_MAX]; void rb_bson_generate_machine_id(VALUE rb_md5_class, char *rb_bson_machine_id) { VALUE digest = rb_funcall(rb_md5_class, rb_intern("digest"), 1, rb_str_new2(rb_bson_machine_id)); memcpy(rb_bson_machine_id_hash, RSTRING_PTR(digest), RSTRING_LEN(digest)); } /** * Generate the next object id. */ VALUE rb_bson_object_id_generator_next(int argc, VALUE* args, VALUE self) { char bytes[12]; uint32_t t; uint32_t c; uint16_t pid = BSON_UINT16_TO_BE(getpid()); if (argc == 0 || (argc == 1 && *args == Qnil)) { t = BSON_UINT32_TO_BE((int) time(NULL)); } else { t = BSON_UINT32_TO_BE(NUM2ULONG(rb_funcall(*args, rb_intern("to_i"), 0))); } c = BSON_UINT32_TO_BE(rb_bson_object_id_counter << 8); memcpy(&bytes, &t, 4); memcpy(&bytes[4], rb_bson_machine_id_hash, 3); memcpy(&bytes[7], &pid, 2); memcpy(&bytes[9], &c, 3); rb_bson_object_id_counter++; return rb_str_new(bytes, 12); } /** * Returns a Ruby constant nested one level, e.g. BSON::Document. */ VALUE pvt_const_get_2(const char *c1, const char *c2) { return rb_const_get(rb_const_get(rb_cObject, rb_intern(c1)), rb_intern(c2)); } /** * Returns a Ruby constant nested two levels, e.g. BSON::Regexp::Raw. */ VALUE pvt_const_get_3(const char *c1, const char *c2, const char *c3) { return rb_const_get(pvt_const_get_2(c1, c2), rb_intern(c3)); } /** * Returns the value of the :mode option, or the default if the option is not * specified. Raises ArgumentError if the value is not one of nil or :bson. * A future version of bson-ruby is expected to also support :ruby and :ruby! * values. Returns one of the BSON_MODE_* values. */ int pvt_get_mode_option(int argc, VALUE *argv) { VALUE opts; VALUE mode; rb_scan_args(argc, argv, ":", &opts); if (NIL_P(opts)) { return BSON_MODE_DEFAULT; } else { mode = rb_hash_lookup(opts, ID2SYM(rb_intern("mode"))); if (mode == Qnil) { return BSON_MODE_DEFAULT; } else if (mode == ID2SYM(rb_intern("bson"))) { return BSON_MODE_BSON; } else { rb_raise(rb_eArgError, "Invalid value for :mode option: %s", RSTRING_PTR(rb_funcall(mode, rb_intern("inspect"), 0))); } } } bson-ruby-4.15.0/ext/bson/write.c000066400000000000000000000561041423026727100165720ustar00rootroot00000000000000/* * Copyright (C) 2009-2020 MongoDB Inc. * * 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. */ #include "bson-native.h" #include typedef struct{ byte_buffer_t *b; VALUE buffer; VALUE validating_keys; } put_hash_context; static void pvt_replace_int32(byte_buffer_t *b, int32_t position, int32_t newval); static void pvt_put_field(byte_buffer_t *b, VALUE rb_buffer, VALUE val, VALUE validating_keys); static void pvt_put_byte(byte_buffer_t *b, const char byte); static void pvt_put_int32(byte_buffer_t *b, const int32_t i32); static void pvt_put_uint32(byte_buffer_t *b, const uint32_t i32); static void pvt_put_int64(byte_buffer_t *b, const int64_t i); static void pvt_put_double(byte_buffer_t *b, double f); static void pvt_put_cstring(byte_buffer_t *b, const char *str, int32_t length, const char *data_type); static void pvt_put_bson_key(byte_buffer_t *b, VALUE string, VALUE validating_keys); static VALUE pvt_bson_byte_buffer_put_bson_partial_string(VALUE self, const char *str, int32_t length); static VALUE pvt_bson_byte_buffer_put_binary_string(VALUE self, const char *str, int32_t length); static int fits_int32(int64_t i64){ return i64 >= INT32_MIN && i64 <= INT32_MAX; } void pvt_put_field(byte_buffer_t *b, VALUE rb_buffer, VALUE val, VALUE validating_keys){ switch(TYPE(val)){ case T_BIGNUM: case T_FIXNUM:{ int64_t i64= NUM2LL(val); if(fits_int32(i64)){ pvt_put_int32(b, (int32_t)i64); }else{ pvt_put_int64(b, i64); } break; } case T_FLOAT: pvt_put_double(b, NUM2DBL(val)); break; case T_ARRAY: rb_bson_byte_buffer_put_array(rb_buffer, val, validating_keys); break; case T_TRUE: pvt_put_byte(b, 1); break; case T_FALSE: pvt_put_byte(b, 0); break; case T_HASH: rb_bson_byte_buffer_put_hash(rb_buffer, val, validating_keys); break; default:{ rb_funcall(val, rb_intern("to_bson"), 2, rb_buffer, validating_keys); break; } } } void pvt_put_byte(byte_buffer_t *b, const char byte) { ENSURE_BSON_WRITE(b, 1); *WRITE_PTR(b) = byte; b->write_position += 1; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_put_byte(VALUE self, VALUE byte) { byte_buffer_t *b; const char *str; size_t length; if (!RB_TYPE_P(byte, T_STRING)) rb_raise(rb_eArgError, "A string argument is required for put_byte"); str = RSTRING_PTR(byte); length = RSTRING_LEN(byte); if (length != 1) { rb_raise(rb_eArgError, "put_byte requires a string of length 1"); } TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); ENSURE_BSON_WRITE(b, 1); memcpy(WRITE_PTR(b), str, 1); b->write_position += 1; return self; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_put_bytes(VALUE self, VALUE bytes) { byte_buffer_t *b; const char *str; size_t length; if (!RB_TYPE_P(bytes, T_STRING) && !RB_TYPE_P(bytes, RUBY_T_DATA)) rb_raise(rb_eArgError, "Invalid input"); str = RSTRING_PTR(bytes); length = RSTRING_LEN(bytes); TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); ENSURE_BSON_WRITE(b, length); memcpy(WRITE_PTR(b), str, length); b->write_position += length; return self; } /* write the byte denoting the BSON type for the passed object */ void pvt_put_type_byte(byte_buffer_t *b, VALUE val){ char type_byte; switch (TYPE(val)){ case T_BIGNUM: case T_FIXNUM: if (fits_int32(NUM2LL(val))) { type_byte = BSON_TYPE_INT32; } else { type_byte = BSON_TYPE_INT64; } break; case T_STRING: type_byte = BSON_TYPE_STRING; break; case T_ARRAY: type_byte = BSON_TYPE_ARRAY; break; case T_TRUE: case T_FALSE: type_byte = BSON_TYPE_BOOLEAN; break; case T_HASH: type_byte = BSON_TYPE_DOCUMENT; break; case T_FLOAT: type_byte = BSON_TYPE_DOUBLE; break; default: { VALUE type; VALUE responds = rb_funcall(val, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("bson_type"))); if (!RTEST(responds)) { VALUE klass = pvt_const_get_3("BSON", "Error", "UnserializableClass"); VALUE val_str = rb_funcall(val, rb_intern("to_s"), 0); rb_raise(klass, "Value does not define its BSON serialized type: %s", RSTRING_PTR(val_str)); } type = rb_funcall(val, rb_intern("bson_type"), 0); type_byte = *RSTRING_PTR(type); RB_GC_GUARD(type); break; } } pvt_put_byte(b, type_byte); } /** * Write a binary string (i.e. one potentially including null bytes) * to byte buffer. length is the number of bytes to write. * If str is null terminated, length does not include the terminating null. */ VALUE pvt_bson_byte_buffer_put_binary_string(VALUE self, const char *str, int32_t length) { byte_buffer_t *b; int32_t length_le; rb_bson_utf8_validate(str, length, true, "String"); /* Even though we are storing binary data, and including the length * of it, the bson spec still demands the (useless) trailing null. */ length_le = BSON_UINT32_TO_LE(length + 1); TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); ENSURE_BSON_WRITE(b, length + 5); memcpy(WRITE_PTR(b), &length_le, 4); b->write_position += 4; memcpy(WRITE_PTR(b), str, length); b->write_position += length; pvt_put_byte(b, 0); return self; } /** * Encodes +string+ to UTF-8. If +string+ is already in UTF-8, validates that * it contains only valid UTF-8 bytes/byte sequences. * * Raises EncodingError on failure. */ static VALUE pvt_bson_encode_to_utf8(VALUE string) { VALUE existing_encoding_name; VALUE encoding; VALUE utf8_string; const char *str; int32_t length; existing_encoding_name = rb_funcall( rb_funcall(string, rb_intern("encoding"), 0), rb_intern("name"), 0); if (strcmp(RSTRING_PTR(existing_encoding_name), "UTF-8") == 0) { utf8_string = string; str = RSTRING_PTR(utf8_string); length = RSTRING_LEN(utf8_string); rb_bson_utf8_validate(str, length, true, "String"); } else { encoding = rb_enc_str_new_cstr("UTF-8", rb_utf8_encoding()); utf8_string = rb_funcall(string, rb_intern("encode"), 1, encoding); RB_GC_GUARD(encoding); } return utf8_string; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_put_string(VALUE self, VALUE string) { VALUE utf8_string; const char *str; int32_t length; utf8_string = pvt_bson_encode_to_utf8(string); /* At this point utf8_string contains valid utf-8 byte sequences only */ str = RSTRING_PTR(utf8_string); length = RSTRING_LEN(utf8_string); RB_GC_GUARD(utf8_string); return pvt_bson_byte_buffer_put_binary_string(self, str, length); } /** * Writes a string (which may form part of a BSON object) to the byte buffer. * * Note: the string may not contain null bytes, and must be null-terminated. * length is the number of bytes to write and does not include the null * terminator. */ VALUE pvt_bson_byte_buffer_put_bson_partial_string(VALUE self, const char *str, int32_t length) { byte_buffer_t *b; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); pvt_put_cstring(b, str, length, "String"); return self; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_put_cstring(VALUE self, VALUE obj) { VALUE string; const char *str; int32_t length; switch (TYPE(obj)) { case T_STRING: string = pvt_bson_encode_to_utf8(obj); break; case T_SYMBOL: string = rb_sym2str(obj); break; case T_FIXNUM: string = rb_fix2str(obj, 10); break; default: rb_raise(rb_eTypeError, "Invalid type for put_cstring"); } str = RSTRING_PTR(string); length = RSTRING_LEN(string); RB_GC_GUARD(string); return pvt_bson_byte_buffer_put_bson_partial_string(self, str, length); } /** * Writes a string (which may form part of a BSON object) to the byte buffer. * * Note: the string may not contain null bytes, and must be null-terminated. * length is the number of bytes to write and does not include the null * terminator. * * data_type is the type of data being written, e.g. "String" or "Key". */ void pvt_put_cstring(byte_buffer_t *b, const char *str, int32_t length, const char *data_type) { int bytes_to_write; rb_bson_utf8_validate(str, length, false, data_type); bytes_to_write = length + 1; ENSURE_BSON_WRITE(b, bytes_to_write); memcpy(WRITE_PTR(b), str, bytes_to_write); b->write_position += bytes_to_write; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_put_symbol(VALUE self, VALUE symbol) { VALUE symbol_str = rb_sym_to_s(symbol); const char *str = RSTRING_PTR(symbol_str); const int32_t length = RSTRING_LEN(symbol_str); RB_GC_GUARD(symbol_str); return pvt_bson_byte_buffer_put_binary_string(self, str, length); } /** * Write a hash key to the byte buffer, validating it if requested */ void pvt_put_bson_key(byte_buffer_t *b, VALUE string, VALUE validating_keys){ char *c_str = RSTRING_PTR(string); size_t length = RSTRING_LEN(string); if (RTEST(validating_keys)) { if (length > 0 && (c_str[0] == '$' || memchr(c_str, '.', length))) { rb_exc_raise(rb_funcall(rb_bson_illegal_key, rb_intern("new"), 1, string)); } } pvt_put_cstring(b, c_str, length, "Key"); } void pvt_replace_int32(byte_buffer_t *b, int32_t position, int32_t newval) { const int32_t i32 = BSON_UINT32_TO_LE(newval); memcpy(READ_PTR(b) + position, &i32, 4); } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_replace_int32(VALUE self, VALUE position, VALUE newval) { byte_buffer_t *b; long _position; _position = NUM2LONG(position); if (_position < 0) { rb_raise(rb_eArgError, "Position given to replace_int32 cannot be negative: %ld", _position); } TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); if (b->write_position < 4) { rb_raise(rb_eArgError, "Buffer does not have enough data to use replace_int32"); } if ((size_t) _position > b->write_position - 4) { rb_raise(rb_eArgError, "Position given to replace_int32 is out of bounds: %ld", _position); } pvt_replace_int32(b, _position, NUM2LONG(newval)); return self; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_put_int32(VALUE self, VALUE i) { byte_buffer_t *b; const int32_t i32 = NUM2INT(i); TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); pvt_put_int32(b, i32); return self; } void pvt_put_int32(byte_buffer_t *b, const int32_t i) { const int32_t i32 = BSON_UINT32_TO_LE(i); ENSURE_BSON_WRITE(b, 4); memcpy(WRITE_PTR(b), &i32, 4); b->write_position += 4; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_put_uint32(VALUE self, VALUE i) { byte_buffer_t *b; int64_t temp; uint32_t i32; if (RB_TYPE_P(i, T_FLOAT)) { rb_raise(rb_eArgError, "put_uint32: incorrect type: float, expected: integer"); } temp = NUM2LL(i); if (temp < 0 || temp > UINT32_MAX) { rb_raise(rb_eRangeError, "Number %lld is out of range [0, 2^32)", (long long)temp); } i32 = NUM2UINT(i); TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); pvt_put_uint32(b, i32); return self; } void pvt_put_uint32(byte_buffer_t *b, const uint32_t i) { const uint32_t i32 = BSON_UINT32_TO_LE(i); ENSURE_BSON_WRITE(b, 4); memcpy(WRITE_PTR(b), &i32, 4); b->write_position += 4; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_put_int64(VALUE self, VALUE i) { byte_buffer_t *b; const int64_t i64 = NUM2LL(i); TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); pvt_put_int64(b, i64); return self; } void pvt_put_int64(byte_buffer_t *b, const int64_t i) { const int64_t i64 = BSON_UINT64_TO_LE(i); ENSURE_BSON_WRITE(b, 8); memcpy(WRITE_PTR(b), &i64, 8); b->write_position += 8; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_put_double(VALUE self, VALUE f) { byte_buffer_t *b; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); pvt_put_double(b, NUM2DBL(f)); return self; } void pvt_put_double(byte_buffer_t *b, double f) { const double d = BSON_DOUBLE_TO_LE(f); ENSURE_BSON_WRITE(b, 8); memcpy(WRITE_PTR(b), &d, 8); b->write_position += 8; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_put_decimal128(VALUE self, VALUE low, VALUE high) { byte_buffer_t *b; const int64_t low64 = BSON_UINT64_TO_LE(NUM2ULL(low)); const int64_t high64 = BSON_UINT64_TO_LE(NUM2ULL(high)); TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); ENSURE_BSON_WRITE(b, 16); memcpy(WRITE_PTR(b), &low64, 8); b->write_position += 8; memcpy(WRITE_PTR(b), &high64, 8); b->write_position += 8; return self; } static int put_hash_callback(VALUE key, VALUE val, VALUE context){ VALUE buffer = ((put_hash_context*)context)->buffer; VALUE validating_keys = ((put_hash_context*)context)->validating_keys; byte_buffer_t *b = ((put_hash_context*)context)->b; VALUE key_str; pvt_put_type_byte(b, val); switch(TYPE(key)){ case T_STRING: pvt_put_bson_key(b, key, validating_keys); break; case T_SYMBOL: key_str = rb_sym_to_s(key); RB_GC_GUARD(key_str); pvt_put_bson_key(b, key_str, validating_keys); break; default: rb_bson_byte_buffer_put_cstring(buffer, rb_funcall(key, rb_intern("to_bson_key"), 1, validating_keys)); } pvt_put_field(b, buffer, val, validating_keys); return ST_CONTINUE; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_put_hash(VALUE self, VALUE hash, VALUE validating_keys){ byte_buffer_t *b = NULL; put_hash_context context = { NULL }; size_t position = 0; size_t new_position = 0; int32_t new_length = 0; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); Check_Type(hash, T_HASH); position = READ_SIZE(b); /* insert length placeholder */ pvt_put_int32(b, 0); context.buffer = self; context.validating_keys = validating_keys; context.b = b; rb_hash_foreach(hash, put_hash_callback, (VALUE)&context); pvt_put_byte(b, 0); /* update length placeholder with actual value */ new_position = READ_SIZE(b); new_length = new_position - position; pvt_replace_int32(b, position, new_length); return self; } static const char *index_strings[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126", "127", "128", "129", "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142", "143", "144", "145", "146", "147", "148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175", "176", "177", "178", "179", "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", "190", "191", "192", "193", "194", "195", "196", "197", "198", "199", "200", "201", "202", "203", "204", "205", "206", "207", "208", "209", "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", "250", "251", "252", "253", "254", "255", "256", "257", "258", "259", "260", "261", "262", "263", "264", "265", "266", "267", "268", "269", "270", "271", "272", "273", "274", "275", "276", "277", "278", "279", "280", "281", "282", "283", "284", "285", "286", "287", "288", "289", "290", "291", "292", "293", "294", "295", "296", "297", "298", "299", "300", "301", "302", "303", "304", "305", "306", "307", "308", "309", "310", "311", "312", "313", "314", "315", "316", "317", "318", "319", "320", "321", "322", "323", "324", "325", "326", "327", "328", "329", "330", "331", "332", "333", "334", "335", "336", "337", "338", "339", "340", "341", "342", "343", "344", "345", "346", "347", "348", "349", "350", "351", "352", "353", "354", "355", "356", "357", "358", "359", "360", "361", "362", "363", "364", "365", "366", "367", "368", "369", "370", "371", "372", "373", "374", "375", "376", "377", "378", "379", "380", "381", "382", "383", "384", "385", "386", "387", "388", "389", "390", "391", "392", "393", "394", "395", "396", "397", "398", "399", "400", "401", "402", "403", "404", "405", "406", "407", "408", "409", "410", "411", "412", "413", "414", "415", "416", "417", "418", "419", "420", "421", "422", "423", "424", "425", "426", "427", "428", "429", "430", "431", "432", "433", "434", "435", "436", "437", "438", "439", "440", "441", "442", "443", "444", "445", "446", "447", "448", "449", "450", "451", "452", "453", "454", "455", "456", "457", "458", "459", "460", "461", "462", "463", "464", "465", "466", "467", "468", "469", "470", "471", "472", "473", "474", "475", "476", "477", "478", "479", "480", "481", "482", "483", "484", "485", "486", "487", "488", "489", "490", "491", "492", "493", "494", "495", "496", "497", "498", "499", "500", "501", "502", "503", "504", "505", "506", "507", "508", "509", "510", "511", "512", "513", "514", "515", "516", "517", "518", "519", "520", "521", "522", "523", "524", "525", "526", "527", "528", "529", "530", "531", "532", "533", "534", "535", "536", "537", "538", "539", "540", "541", "542", "543", "544", "545", "546", "547", "548", "549", "550", "551", "552", "553", "554", "555", "556", "557", "558", "559", "560", "561", "562", "563", "564", "565", "566", "567", "568", "569", "570", "571", "572", "573", "574", "575", "576", "577", "578", "579", "580", "581", "582", "583", "584", "585", "586", "587", "588", "589", "590", "591", "592", "593", "594", "595", "596", "597", "598", "599", "600", "601", "602", "603", "604", "605", "606", "607", "608", "609", "610", "611", "612", "613", "614", "615", "616", "617", "618", "619", "620", "621", "622", "623", "624", "625", "626", "627", "628", "629", "630", "631", "632", "633", "634", "635", "636", "637", "638", "639", "640", "641", "642", "643", "644", "645", "646", "647", "648", "649", "650", "651", "652", "653", "654", "655", "656", "657", "658", "659", "660", "661", "662", "663", "664", "665", "666", "667", "668", "669", "670", "671", "672", "673", "674", "675", "676", "677", "678", "679", "680", "681", "682", "683", "684", "685", "686", "687", "688", "689", "690", "691", "692", "693", "694", "695", "696", "697", "698", "699", "700", "701", "702", "703", "704", "705", "706", "707", "708", "709", "710", "711", "712", "713", "714", "715", "716", "717", "718", "719", "720", "721", "722", "723", "724", "725", "726", "727", "728", "729", "730", "731", "732", "733", "734", "735", "736", "737", "738", "739", "740", "741", "742", "743", "744", "745", "746", "747", "748", "749", "750", "751", "752", "753", "754", "755", "756", "757", "758", "759", "760", "761", "762", "763", "764", "765", "766", "767", "768", "769", "770", "771", "772", "773", "774", "775", "776", "777", "778", "779", "780", "781", "782", "783", "784", "785", "786", "787", "788", "789", "790", "791", "792", "793", "794", "795", "796", "797", "798", "799", "800", "801", "802", "803", "804", "805", "806", "807", "808", "809", "810", "811", "812", "813", "814", "815", "816", "817", "818", "819", "820", "821", "822", "823", "824", "825", "826", "827", "828", "829", "830", "831", "832", "833", "834", "835", "836", "837", "838", "839", "840", "841", "842", "843", "844", "845", "846", "847", "848", "849", "850", "851", "852", "853", "854", "855", "856", "857", "858", "859", "860", "861", "862", "863", "864", "865", "866", "867", "868", "869", "870", "871", "872", "873", "874", "875", "876", "877", "878", "879", "880", "881", "882", "883", "884", "885", "886", "887", "888", "889", "890", "891", "892", "893", "894", "895", "896", "897", "898", "899", "900", "901", "902", "903", "904", "905", "906", "907", "908", "909", "910", "911", "912", "913", "914", "915", "916", "917", "918", "919", "920", "921", "922", "923", "924", "925", "926", "927", "928", "929", "930", "931", "932", "933", "934", "935", "936", "937", "938", "939", "940", "941", "942", "943", "944", "945", "946", "947", "948", "949", "950", "951", "952", "953", "954", "955", "956", "957", "958", "959", "960", "961", "962", "963", "964", "965", "966", "967", "968", "969", "970", "971", "972", "973", "974", "975", "976", "977", "978", "979", "980", "981", "982", "983", "984", "985", "986", "987", "988", "989", "990", "991", "992", "993", "994", "995", "996", "997", "998", "999"}; /** * Writes an array index to the byte buffer. */ void pvt_put_array_index(byte_buffer_t *b, int32_t index) { char buffer[16]; const char *c_str = NULL; size_t length; if (index < 1000) { c_str = index_strings[index]; } else { c_str = buffer; snprintf(buffer, sizeof(buffer), "%d", index); } length = strlen(c_str) + 1; ENSURE_BSON_WRITE(b, length); memcpy(WRITE_PTR(b), c_str, length); b->write_position += length; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_put_array(VALUE self, VALUE array, VALUE validating_keys){ byte_buffer_t *b = NULL; size_t new_position = 0; int32_t new_length = 0; size_t position = 0; VALUE *array_element = NULL; TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b); Check_Type(array, T_ARRAY); position = READ_SIZE(b); /* insert length placeholder */ pvt_put_int32(b, 0); array_element = RARRAY_PTR(array); for(int32_t index=0; index < RARRAY_LEN(array); index++, array_element++){ pvt_put_type_byte(b, *array_element); pvt_put_array_index(b, index); pvt_put_field(b, self, *array_element, validating_keys); } pvt_put_byte(b, 0); /* update length placeholder */ new_position = READ_SIZE(b); new_length = new_position - position; pvt_replace_int32(b, position, new_length); return self; } bson-ruby-4.15.0/gem-public_cert.pem000066400000000000000000000023651423026727100172770ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDfDCCAmSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBCMRQwEgYDVQQDDAtkcml2 ZXItcnVieTEVMBMGCgmSJomT8ixkARkWBTEwZ2VuMRMwEQYKCZImiZPyLGQBGRYD Y29tMB4XDTIyMDMzMDE5MTcwMloXDTIzMDMzMDE5MTcwMlowQjEUMBIGA1UEAwwL ZHJpdmVyLXJ1YnkxFTATBgoJkiaJk/IsZAEZFgUxMGdlbjETMBEGCgmSJomT8ixk ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANFdSAa8fRm1 bAM9za6Z0fAH4g02bqM1NGnw8zJQrE/PFrFfY6IFCT2AsLfOwr1maVm7iU1+kdVI IQ+iI/9+E+ArJ+rbGV3dDPQ+SLl3mLT+vXjfjcxMqI2IW6UuVtt2U3Rxd4QU0kdT JxmcPYs5fDN6BgYc6XXgUjy3m+Kwha2pGctdciUOwEfOZ4RmNRlEZKCMLRHdFP8j 4WTnJSGfXDiuoXICJb5yOPOZPuaapPSNXp93QkUdsqdKC32I+KMpKKYGBQ6yisfA 5MyVPPCzLR1lP5qXVGJPnOqUAkvEUfCahg7EP9tI20qxiXrR6TSEraYhIFXL0EGY u8KAcPHm5KkCAwEAAaN9MHswCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O BBYEFFt3WbF+9JpUjAoj62cQBgNb8HzXMCAGA1UdEQQZMBeBFWRyaXZlci1ydWJ5 QDEwZ2VuLmNvbTAgBgNVHRIEGTAXgRVkcml2ZXItcnVieUAxMGdlbi5jb20wDQYJ KoZIhvcNAQEFBQADggEBAM0s7jz2IGD8Ms035b1tMnbNP2CBPq3pen3KQj7IkGF7 x8LPDdOqUj4pUMLeefntX/PkSvwROo677TnWK6+GLayGm5xLHrZH3svybC6QtqTR mVOLUoZ4TgUmtnMUa/ZvgrIsOeiCysjSf4WECuw7g+LE6jcpLepgYTLk2u1+5SgH JVENj0BMkdeZIKkc2G97DSx3Zrmz7QWAaH+99XlajJbfcgvhDso+ffQkTBlOgLBg +WyKQ+QTIdtDiyf2LQmxWnxt/W1CmScjdLS7/yXGkkB/D9Uy+sJD747O/B9P238Q XnerrtyOu04RsWDvaZkCwSDVzoqfICh4CP1mlde73Ts= -----END CERTIFICATE----- bson-ruby-4.15.0/lib/000077500000000000000000000000001423026727100142735ustar00rootroot00000000000000bson-ruby-4.15.0/lib/bson.rb000066400000000000000000000055271423026727100155720ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "bson/environment" # The core namespace for all BSON related behaviour. # # @since 0.0.0 module BSON # Create a new object id from a string using ObjectId.from_string # # @example Create an object id from the string. # BSON::ObjectId(id) # # @param [ String ] string The string to create the id from. # # @raise [ BSON::ObjectId::Invalid ] If the provided string is invalid. # # @return [ BSON::ObjectId ] The new object id. # # @see ObjectId.from_string def self.ObjectId(string) self::ObjectId.from_string(string) end # Constant for binary string encoding. # # @since 2.0.0 BINARY = "BINARY" # Constant for bson types that don't actually serialize a value. # # @since 2.0.0 NO_VALUE = ::String.new(encoding: BINARY).freeze # Constant for a null byte (0x00). # # @since 2.0.0 NULL_BYTE = ::String.new(0.chr, encoding: BINARY).freeze # Constant for UTF-8 string encoding. # # @since 2.0.0 UTF8 = "UTF-8" end require "bson/config" require "bson/error" require "bson/registry" require "bson/specialized" require "bson/json" require "bson/int32" require "bson/int64" require "bson/integer" require "bson/array" require "bson/binary" require "bson/boolean" require "bson/code" require "bson/code_with_scope" require "bson/date" require "bson/date_time" require "bson/db_pointer" require "bson/decimal128" require "bson/big_decimal" require "bson/document" require "bson/ext_json" require "bson/false_class" require "bson/float" require "bson/hash" require "bson/dbref" require "bson/open_struct" require "bson/max_key" require "bson/min_key" require "bson/nil_class" require "bson/object" require "bson/object_id" require "bson/regexp" require "bson/string" require "bson/symbol" require "bson/time" require "bson/timestamp" require "bson/true_class" require "bson/undefined" require "bson/version" # If we are using JRuby, attempt to load the Java extensions, if we are using # MRI or Rubinius, attempt to load the C extensions. # # @since 2.0.0 begin if BSON::Environment.jruby? require "bson-ruby.jar" JRuby::Util.load_ext("org.bson.NativeService") else require "bson_native" end rescue LoadError => e $stderr.puts("Failed to load the necessary extensions: #{e.class}: #{e}") raise end bson-ruby-4.15.0/lib/bson/000077500000000000000000000000001423026727100152345ustar00rootroot00000000000000bson-ruby-4.15.0/lib/bson/active_support.rb000066400000000000000000000012731423026727100206330ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2018-2020 MongoDB Inc. # # 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. # Require this file if using BSON with ActiveSupport. require "bson/time_with_zone" bson-ruby-4.15.0/lib/bson/array.rb000066400000000000000000000117211423026727100167010ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding and decoding arrays to # and from raw bytes as specified by the BSON spec. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 module Array # An array is type 0x04 in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(4.chr, encoding: BINARY).freeze # Get the array as encoded BSON. # # @example Get the array as encoded BSON. # [ 1, 2, 3 ].to_bson # # @note Arrays are encoded as documents, where the index of the value in # the array is the actual key. # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) if buffer.respond_to?(:put_array) buffer.put_array(self, validating_keys) else position = buffer.length buffer.put_int32(0) each_with_index do |value, index| unless value.respond_to?(:bson_type) raise Error::UnserializableClass, "Array element at position #{index} does not define its BSON serialized type: #{value}" end buffer.put_byte(value.bson_type) buffer.put_cstring(index.to_s) value.to_bson(buffer, validating_keys) end buffer.put_byte(NULL_BYTE) buffer.replace_int32(position, buffer.length - position) end end # Convert the array to an object id. This will only work for arrays of size # 12 where the elements are all strings. # # @example Convert the array to an object id. # array.to_bson_object_id # # @note This is used for repairing legacy bson data. # # @raise [ BSON::ObjectId::Invalid ] If the array is not 12 elements. # # @return [ String ] The raw object id bytes. # # @since 2.0.0 def to_bson_object_id ObjectId.repair(self) { pack("C*") } end # Converts the array to a normalized value in a BSON document. # # @example Convert the array to a normalized value. # array.to_bson_normalized_value # # @return [ Array ] The normalized array. # # @since 3.0.0 def to_bson_normalized_value map { |value| value.to_bson_normalized_value } end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # This method recursively invokes +as_extended_json+ with the provided # options on each array element. # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Array ] This array converted to extended json representation. def as_extended_json(**options) map do |item| item.as_extended_json(**options) end end module ClassMethods # Deserialize the array from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ Array ] The decoded array. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def from_bson(buffer, **options) if buffer.respond_to?(:get_array) buffer.get_array(**options) else array = new start_position = buffer.read_position expected_byte_size = buffer.get_int32 while (type = buffer.get_byte) != NULL_BYTE buffer.get_cstring cls = BSON::Registry.get(type) value = if options.empty? cls.from_bson(buffer) else cls.from_bson(buffer, **options) end array << value end actual_byte_size = buffer.read_position - start_position if actual_byte_size != expected_byte_size raise Error::BSONDecodeError, "Expected array to take #{expected_byte_size} bytes but it took #{actual_byte_size} bytes" end array end end end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, ::Array) end # Enrich the core Array class with this module. # # @since 2.0.0 ::Array.send(:include, Array) ::Array.send(:extend, Array::ClassMethods) end bson-ruby-4.15.0/lib/bson/big_decimal.rb000066400000000000000000000042321423026727100200010ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2021 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding and decoding BigDecimals # to and from raw bytes as specified by the BSON spec. # # @see http://bsonspec.org/#/specification module BigDecimal # BigDecimals are serialized as Decimal128s under the hood. A Decimal128 # is type 0x13 in the BSON spec. BSON_TYPE = ::String.new(19.chr, encoding: BINARY).freeze # Get the BigDecimal as encoded BSON. # # @example Get the BigDecimal as encoded BSON. # BigDecimal("1").to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) BSON::Decimal128.new(to_s).to_bson(buffer, validating_keys) end # Get the BSON type for BigDecimal. This is the same BSON type as # BSON::Decimal128. def bson_type BSON_TYPE end module ClassMethods # Deserialize the BigDecimal from raw BSON bytes. # # @example Get the BigDecimal from BSON. # BigDecimal.from_bson(bson) # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ BigDecimal ] The decimal object. def from_bson(buffer, **options) Decimal128.from_bson(buffer, **options).to_big_decimal end end end # Enrich the core BigDecimal class with this module. ::BigDecimal.send(:include, BigDecimal) ::BigDecimal.send(:extend, BigDecimal::ClassMethods) end bson-ruby-4.15.0/lib/bson/binary.rb000066400000000000000000000316011423026727100170460ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. require 'base64' module BSON # Represents binary data. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 class Binary include JSON # A binary is type 0x05 in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(5.chr, encoding: BINARY).freeze # The mappings of subtypes to their single byte identifiers. # # @note subtype 6 (ciphertext) is used for the Client-Side Encryption # feature. Data represented by this subtype is often encrypted, but # may also be plaintext. All instances of this subtype necessary for # Client-Side Encryption will be created internally by the Ruby driver. # An application should not create new BSON::Binary objects of this subtype. # # @since 2.0.0 SUBTYPES = { :generic => 0.chr, :function => 1.chr, :old => 2.chr, :uuid_old => 3.chr, :uuid => 4.chr, :md5 => 5.chr, :ciphertext => 6.chr, :column => 7.chr, :user => 128.chr, }.freeze # The mappings of single byte subtypes to their symbol counterparts. # # @since 2.0.0 TYPES = SUBTYPES.invert.freeze # @return [ String ] The raw binary data. # # The string is always stored in BINARY encoding. # # @since 2.0.0 attr_reader :data # @return [ Symbol ] The binary type. # # @since 2.0.0 attr_reader :type # Determine if this binary object is equal to another object. # # @example Check the binary equality. # binary == other # # @param [ Object ] other The object to compare against. # # @return [ true, false ] If the objects are equal. # # @since 2.0.0 def ==(other) return false unless other.is_a?(Binary) type == other.type && data == other.data end alias eql? == # Generates a Fixnum hash value for this object. # # Allows using Binary as hash keys. # # @return [ Fixnum ] # # @since 2.3.1 def hash data.hash + type.hash end # Get the binary as JSON hash data. # # @example Get the binary as a JSON hash. # binary.as_json # # @return [ Hash ] The binary as a JSON hash. # # @since 2.0.0 # @deprecated Use as_extended_json instead. def as_json(*args) as_extended_json end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash ] The extended json representation. def as_extended_json(**options) subtype = SUBTYPES[type].each_byte.map { |c| c.to_s(16) }.join if subtype.length == 1 subtype = "0#{subtype}" end value = Base64.encode64(data).strip if options[:mode] == :legacy { "$binary" => value, "$type" => subtype } else { "$binary" => {'base64' => value, "subType" => subtype }} end end # Instantiate the new binary object. # # This method accepts a string in any encoding; however, if a string is # of a non-BINARY encoding, the encoding is set to BINARY. This does not # change the bytes of the string but it means that applications referencing # the data of a Binary instance cannot assume it is in a non-binary # encoding, even if the string given to the constructor was in such an # encoding. # # @example Instantiate a binary. # BSON::Binary.new(data, :md5) # # @param [ String ] data The raw binary data. # @param [ Symbol ] type The binary type. # # @since 2.0.0 def initialize(data = "", type = :generic) validate_type!(type) # The Binary class used to force encoding to BINARY when serializing to # BSON. Instead of doing that during serialization, perform this # operation during Binary construction to make it clear that once # the string is given to the Binary, the data is treated as a binary # string and not a text string in any encoding. unless data.encoding == Encoding.find('BINARY') data = data.dup.force_encoding('BINARY') end @data = data @type = type end # Get a nice string for use with object inspection. # # @example Inspect the binary. # object_id.inspect # # @return [ String ] The binary in form BSON::Binary:object_id # # @since 2.3.0 def inspect "" end # Returns a string representation of the UUID stored in this Binary. # # If the Binary is of subtype 4 (:uuid), this method returns the UUID # in RFC 4122 format. If the representation parameter is provided, it # must be the value :standard as a symbol or a string. # # If the Binary is of subtype 3 (:uuid_old), this method requires that # the representation parameter is provided and is one of :csharp_legacy, # :java_legacy or :python_legacy or the equivalent strings. In this case # the method assumes the Binary stores the UUID in the specified format, # transforms the stored bytes to the standard RFC 4122 representation # and returns the UUID in RFC 4122 format. # # If the Binary is of another subtype, this method raises TypeError. # # @param [ Symbol ] representation How to interpret the UUID. # # @return [ String ] The string representation of the UUID. # # @raise [ TypeError ] If the subtype of Binary is not :uuid nor :uuid_old. # @raise [ ArgumentError ] If the representation other than :standard # is requested for Binary subtype 4 (:uuid), if :standard representation # is requested for Binary subtype 3 (:uuid_old), or if an invalid # representation is requested. # # @api experimental def to_uuid(representation = nil) if representation.is_a?(String) raise ArgumentError, "Representation must be given as a symbol: #{representation}" end case type when :uuid if representation && representation != :standard raise ArgumentError, "Binary of type :uuid can only be stringified to :standard representation, requested: #{representation.inspect}" end data.split('').map { |n| '%02x' % n.ord }.join.sub(/\A(.{8})(.{4})(.{4})(.{4})(.{12})\z/, '\1-\2-\3-\4-\5') when :uuid_old if representation.nil? raise ArgumentError, 'Representation must be specified for BSON::Binary objects of type :uuid_old' end hex = data.split('').map { |n| '%02x' % n.ord }.join case representation when :standard raise ArgumentError, 'BSON::Binary objects of type :uuid_old cannot be stringified to :standard representation' when :csharp_legacy hex.sub(/\A(..)(..)(..)(..)(..)(..)(..)(..)(.{16})\z/, '\4\3\2\1\6\5\8\7\9') when :java_legacy hex.sub(/\A(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)\z/) do |m| "#{$8}#{$7}#{$6}#{$5}#{$4}#{$3}#{$2}#{$1}" + "#{$16}#{$15}#{$14}#{$13}#{$12}#{$11}#{$10}#{$9}" end when :python_legacy hex else raise ArgumentError, "Invalid representation: #{representation}" end.sub(/\A(.{8})(.{4})(.{4})(.{4})(.{12})\z/, '\1-\2-\3-\4-\5') else raise TypeError, "The type of Binary must be :uuid or :uuid_old, this object is: #{type.inspect}" end end # Encode the binary type # # @example Encode the binary. # binary.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) position = buffer.length buffer.put_int32(0) buffer.put_byte(SUBTYPES[type]) buffer.put_int32(data.bytesize) if type == :old buffer.put_bytes(data) buffer.replace_int32(position, buffer.length - position - 5) end # Deserialize the binary data from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ Binary ] The decoded binary data. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def self.from_bson(buffer, **options) length = buffer.get_int32 type_byte = buffer.get_byte type = TYPES[type_byte] if type.nil? raise Error::UnsupportedBinarySubtype, "BSON data contains unsupported binary subtype #{'0x%02x' % type_byte.ord}" end length = buffer.get_int32 if type == :old data = buffer.get_bytes(length) new(data, type) end # Creates a BSON::Binary from a string representation of a UUID. # # The UUID may be given in either 00112233-4455-6677-8899-aabbccddeeff or # 00112233445566778899AABBCCDDEEFF format - specifically, any dashes in # the UUID are removed and both upper and lower case letters are acceptable. # # The input UUID string is always interpreted to be in the RFC 4122 format. # # If representation is not provided, this method creates a BSON::Binary # of subtype 4 (:uuid). If representation is provided, it must be one of # :standard, :csharp_legacy, :java_legacy or :python_legacy. If # representation is :standard, this method creates a subtype 4 (:uuid) # binary which is the same behavior as if representation was not provided. # For other representations, this method creates a Binary of subtype 3 # (:uuid_old) with the UUID converted to the appropriate legacy MongoDB # UUID storage format. # # @param [ String ] uuid The string representation of the UUID. # @param [ Symbol ] representation How to interpret the UUID. # # @return [ Binary ] The binary. # # @raise [ ArgumentError ] If invalid representation is requested. # # @api experimental def self.from_uuid(uuid, representation = nil) if representation.is_a?(String) raise ArgumentError, "Representation must be given as a symbol: #{representation}" end uuid_binary = uuid.gsub('-', '').scan(/../).map(&:hex).map(&:chr).join case representation && representation when nil, :standard new(uuid_binary, :uuid) when :csharp_legacy uuid_binary.sub!(/\A(.)(.)(.)(.)(.)(.)(.)(.)(.{8})\z/, '\4\3\2\1\6\5\8\7\9') new(uuid_binary, :uuid_old) when :java_legacy uuid_binary.sub!(/\A(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)\z/) do |m| "#{$8}#{$7}#{$6}#{$5}#{$4}#{$3}#{$2}#{$1}" + "#{$16}#{$15}#{$14}#{$13}#{$12}#{$11}#{$10}#{$9}" end new(uuid_binary, :uuid_old) when :python_legacy new(uuid_binary, :uuid_old) else raise ArgumentError, "Invalid representation: #{representation}" end end # Raised when providing an invalid type to the Binary. # # @since 2.0.0 class InvalidType < RuntimeError # @!attribute type # @return [ Object ] The invalid type. # @since 2.0.0 attr_reader :type # Instantiate the new error. # # @example Instantiate the error. # InvalidType.new(:error) # # @param [ Object ] type The invalid type. # # @since 2.0.0 def initialize(type) @type = type end # Get the custom error message for the exception. # # @example Get the message. # error.message # # @return [ String ] The error message. # # @since 2.0.0 def message "#{type.inspect} is not a valid binary type. " + "Please use one of #{SUBTYPES.keys.map(&:inspect).join(", ")}." end end private # Validate the provided type is a valid type. # # @api private # # @example Validate the type. # binary.validate_type!(:user) # # @param [ Object ] type The provided type. # # @raise [ InvalidType ] The the type is invalid. # # @since 2.0.0 def validate_type!(type) raise InvalidType.new(type) unless SUBTYPES.has_key?(type) end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, self) end end bson-ruby-4.15.0/lib/bson/boolean.rb000066400000000000000000000031671423026727100172070ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Represents a boolean type, which compares less than any other value in the # specification. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 class Boolean # A boolean is type 0x08 in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(8.chr, encoding: BINARY).freeze # Deserialize a boolean from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ TrueClass, FalseClass ] The decoded boolean. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def self.from_bson(buffer, **options) case v = buffer.get_byte when TrueClass::TRUE_BYTE true when FalseClass::FALSE_BYTE false else raise Error::BSONDecodeError, "Invalid boolean byte value: #{v}" end end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, self) end end bson-ruby-4.15.0/lib/bson/code.rb000066400000000000000000000064761423026727100165100ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Represents a code type, which is a wrapper around javascript code. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 class Code include JSON # A code is type 0x0D in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(13.chr, encoding: BINARY).freeze # @!attribute javascript # @return [ String ] The javascript code. # @since 2.0.0 attr_reader :javascript # Determine if this code object is equal to another object. # # @example Check the code equality. # code == other # # @param [ Object ] other The object to compare against. # # @return [ true, false ] If the objects are equal. # # @since 2.0.0 def ==(other) return false unless other.is_a?(Code) javascript == other.javascript end # Get the code as JSON hash data. # # @example Get the code as a JSON hash. # code.as_json # # @return [ Hash ] The code as a JSON hash. # # @since 2.0.0 # @deprecated Use as_extended_json instead. def as_json(*args) as_extended_json end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash ] The extended json representation. def as_extended_json(**options) { "$code" => javascript } end # Instantiate the new code. # # @example Instantiate the new code. # BSON::Code.new("this.value = 5") # # @param [ String ] javascript The javascript code. # # @since 2.0.0 def initialize(javascript = "") @javascript = javascript end # Encode the javascript code. # # @example Encode the code. # code.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_string(javascript) # @todo: was formerly to_bson_string end # Deserialize code from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ TrueClass, FalseClass ] The decoded code. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def self.from_bson(buffer, **options) new(buffer.get_string) end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, self) end end bson-ruby-4.15.0/lib/bson/code_with_scope.rb000066400000000000000000000107501423026727100207220ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Represents a code with scope, which is a wrapper around javascript code # with variable scope provided. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 class CodeWithScope include JSON # A code with scope is type 0x0F in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(15.chr, encoding: BINARY).freeze # @!attribute javascript # @return [ String ] The javascript code. # @since 2.0.0 # @!attribute scope # @return [ Hash ] The variable scope. # @since 2.0.0 attr_reader :javascript, :scope # Determine if this code with scope object is equal to another object. # # @example Check the code with scope equality. # code_with_scope == other # # @param [ Object ] other The object to compare against. # # @return [ true, false ] If the objects are equal. # # @since 2.0.0 def ==(other) return false unless other.is_a?(CodeWithScope) javascript == other.javascript && scope == other.scope end # Get the code with scope as JSON hash data. # # @example Get the code with scope as a JSON hash. # code_with_scope.as_json # # @return [ Hash ] The code with scope as a JSON hash. # # @since 2.0.0 # @deprecated Use as_extended_json instead. def as_json(*args) as_extended_json end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash ] The extended json representation. def as_extended_json(**options) { "$code" => javascript, "$scope" => scope.as_extended_json(**options) } end # Instantiate the new code with scope. # # @example Instantiate the code with scope. # BSON::CodeWithScope.new("this.value = name", name: "sid") # # @param [ String ] javascript The javascript code. # @param [ Hash ] scope The variable scope. # # @since 2.0.0 def initialize(javascript = "", scope = {}) @javascript = javascript @scope = scope end # Encode the javascript code with scope. # # @example Encode the code with scope. # code_with_scope.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) position = buffer.length buffer.put_int32(0) buffer.put_string(javascript) scope.to_bson(buffer) buffer.replace_int32(position, buffer.length - position) end # Deserialize a code with scope from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ TrueClass, FalseClass ] The decoded code with scope. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def self.from_bson(buffer, **options) # Code with scope has a length (?) field which is not needed for # decoding, but spec tests want this field validated. start_position = buffer.read_position length = buffer.get_int32 javascript = buffer.get_string scope = if options.empty? ::Hash.from_bson(buffer) else ::Hash.from_bson(buffer, **options) end read_bytes = buffer.read_position - start_position if read_bytes != length raise Error::BSONDecodeError, "CodeWithScope invalid: claimed length #{length}, actual length #{read_bytes}" end new(javascript, scope) end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, self) end end bson-ruby-4.15.0/lib/bson/config.rb000066400000000000000000000030061423026727100170250ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2016-2020 MongoDB Inc. # # 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. module BSON # Provides configuration options for the BSON library. # # @since 4.1.0 module Config extend self # Set the configuration option for BSON to validate keys or not. # # @example Set the config option. # BSON::Config.validating_keys = true # # @param [ true, false ] value The value to set. # # @return [ true, false ] The value. # # @since 4.1.0 def validating_keys=(value) @validating_keys = value end # Returns true if BSON will validate the document keys on serialization to # determine if they contain invalid MongoDB values. Invalid keys start with # '$' or contain a '.' in them. # # @example Is BSON validating keys? # BSON::Config.validating_keys? # # @return [ true, false ] If BSON is validating keys? # # @since 4.1.0 def validating_keys? !!(@validating_keys||=nil) end end end bson-ruby-4.15.0/lib/bson/date.rb000066400000000000000000000033741423026727100165050ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. require 'date' module BSON # Julian day of Date 1970-01-01 - UNIX timestamp reference. # # @api private DATE_REFERENCE = ::Date.new(1970, 1, 1).jd # Number of miliseconds in a day. # # @api private MILLISECONDS_IN_DAY = 60 * 60 * 24 * 1_000 # Injects behaviour for encoding date values to raw bytes as specified by # the BSON spec for time. # # @see http://bsonspec.org/#/specification # # @since 2.1.0 module Date # Get the date as encoded BSON. # # @example Get the date as encoded BSON. # Date.new(2012, 1, 1).to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.1.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_int64((jd - DATE_REFERENCE) * MILLISECONDS_IN_DAY) end # Get the BSON type for the date. # # As the date is converted to a time, this returns the BSON type for time. def bson_type ::Time::BSON_TYPE end end # Enrich the core Date class with this module. # # @since 2.1.0 ::Date.send(:include, Date) end bson-ruby-4.15.0/lib/bson/date_time.rb000066400000000000000000000025661423026727100175250ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "time" module BSON # Injects behaviour for encoding date time values to raw bytes as specified by # the BSON spec for time. # # @see http://bsonspec.org/#/specification # # @since 2.1.0 module DateTime # Get the date time as encoded BSON. # # @example Get the date time as encoded BSON. # DateTime.new(2012, 1, 1, 0, 0, 0).to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.1.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) gregorian.to_time.to_bson(buffer) end end # Enrich the core DateTime class with this module. # # @since 2.1.0 ::DateTime.send(:include, DateTime) end bson-ruby-4.15.0/lib/bson/db_pointer.rb000066400000000000000000000064771423026727100177240ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding and decoding DBPointer values to and from # raw bytes as specified by the BSON spec. # # @see http://bsonspec.org/#/specification class DbPointer include JSON # A DBPointer is type 0x0C in the BSON spec. BSON_TYPE = ::String.new(0x0C.chr, encoding: BINARY).freeze # Create a new DBPointer object. # # @param [ String ] ref The database collection name. # @param [ BSON::ObjectId ] id The DBPointer id. def initialize(ref, id) @ref = ref @id = id end # Return the collection name. # # @return [ String ] The database collection name. attr_reader :ref # Return the DbPointer's id. # # @return [ BSON::ObjectId ] The id of the DbPointer instance attr_reader :id # Determine if this DBPointer object is equal to another object. # # @param [ Object ] other The object to compare against. # # @return [ true | false ] If the objects are equal def ==(other) return false unless other.is_a?(DbPointer) ref == other.ref && id == other.id end # Get the DBPointer as JSON hash data # # @return [ Hash ] The DBPointer as a JSON hash. # # @deprecated Use as_extended_json instead. def as_json(*args) as_extended_json end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # @option options [ true | false ] :relaxed Whether to produce relaxed # extended JSON representation. # # @return [ Hash ] The extended json representation. def as_extended_json(**options) {'$dbPointer' => { "$ref" => ref, '$id' => id.as_extended_json }} end # Encode the DBPointer. # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_string(ref) id.to_bson(buffer, validating_keys) buffer end # Deserialize a DBPointer from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # @param [ Hash ] options # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ BSON::DbPointer ] The decoded DBPointer. # # @see http://bsonspec.org/#/specification def self.from_bson(buffer, **options) ref = buffer.get_string id = if options.empty? ObjectId.from_bson(buffer) else ObjectId.from_bson(buffer, **options) end new(ref, id) end # Register this type when the module is loaded. Registry.register(BSON_TYPE, self) end end bson-ruby-4.15.0/lib/bson/dbref.rb000066400000000000000000000106401423026727100166440ustar00rootroot00000000000000# frozen_string_literal: true # encoding: utf-8 # Copyright (C) 2015-2021 MongoDB Inc. # # 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. module BSON # Represents a DBRef document in the database. class DBRef < Document include JSON # The constant for the collection reference field. # # @deprecated COLLECTION = '$ref'.freeze # The constant for the id field. # # @deprecated ID = '$id'.freeze # The constant for the database field. # # @deprecated DATABASE = '$db'.freeze # @return [ String ] collection The collection name. def collection self['$ref'] end # @return [ BSON::ObjectId ] id The referenced document id. def id self['$id'] end # @return [ String ] database The database name. def database self['$db'] end # Get the DBRef as a JSON document # # @example Get the DBRef as a JSON hash. # dbref.as_json # # @return [ Hash ] The max key as a JSON hash. def as_json(*args) {}.update(self) end # Instantiate a new DBRef. # # @example Create the DBRef - hash API. # BSON::DBRef.new({'$ref' => 'users', '$id' => id, '$db' => 'database'}) # # @example Create the DBRef - legacy API. # BSON::DBRef.new('users', id, 'database') # # @param [ Hash | String ] hash_or_collection The DBRef hash, when using # the hash API. It must contain $ref and $id. When using the legacy API, # this parameter must be a String containing the collection name. # @param [ Object ] id The object id, when using the legacy API. # @param [ String ] database The database name, when using the legacy API. def initialize(hash_or_collection, id = nil, database = nil) if hash_or_collection.is_a?(Hash) hash = hash_or_collection unless id.nil? && database.nil? raise ArgumentError, 'When using the hash API, DBRef constructor accepts only one argument' end else warn("BSON::DBRef constructor called with the legacy API - please use the hash API instead") if id.nil? raise ArgumentError, 'When using the legacy constructor API, id must be provided' end hash = { :$ref => hash_or_collection, :$id => id, :$db => database, } end hash = reorder_fields(hash) %w($ref $id).each do |key| unless hash[key] raise ArgumentError, "DBRef must have #{key}: #{hash}" end end unless hash['$ref'].is_a?(String) raise ArgumentError, "The value for key $ref must be a string, got: #{hash['$ref']}" end if db = hash['$db'] unless db.is_a?(String) raise ArgumentError, "The value for key $db must be a string, got: #{hash['$db']}" end end super(hash) end # Converts the DBRef to raw BSON. # # @example Convert the DBRef to raw BSON. # dbref.to_bson # # @param [ BSON::ByteBuffer ] buffer The encoded BSON buffer to append to. # @param [ true, false ] validating_keys Whether keys should be validated when serializing. # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) as_json.to_bson(buffer, validating_keys) end private # Reorder the fields of the given Hash to have $ref first, $id second, # and $db third. The rest of the fields in the hash can come in any # order after that. # # @param [ Hash ] hash The input hash. Must be a valid dbref. # # @return [ Hash ] The hash with it's fields reordered. def reorder_fields(hash) hash = BSON::Document.new(hash) reordered = {} reordered['$ref'] = hash.delete('$ref') reordered['$id'] = hash.delete('$id') if db = hash.delete('$db') reordered['$db'] = db end reordered.update(hash) end end end bson-ruby-4.15.0/lib/bson/decimal128.rb000066400000000000000000000225421423026727100174170ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2016-2020 MongoDB Inc. # # 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. require 'bigdecimal' require 'bson/decimal128/builder' module BSON class Decimal128 include JSON include Comparable # A Decimal128 is type 0x13 in the BSON spec. # # @since 4.2.0 BSON_TYPE = ::String.new(19.chr, encoding: BINARY).freeze # Exponent offset. # # @since 4.2.0 EXPONENT_OFFSET = 6176 # Minimum exponent. # # @since 4.2.0 MIN_EXPONENT = -6176 # Maximum exponent. # # @since 4.2.0 MAX_EXPONENT = 6111 # Maximum digits of precision. # # @since 4.2.0 MAX_DIGITS_OF_PRECISION = 34 # Key for this type when converted to extended json. # # @since 4.2.0 EXTENDED_JSON_KEY = "$numberDecimal" # The native type to which this object can be converted. # # @since 4.2.0 NATIVE_TYPE = BigDecimal # Get the Decimal128 as JSON hash data. # # @example Get the Decimal128 as a JSON hash. # decimal.as_json # # @return [ Hash ] The number as a JSON hash. # # @since 4.2.0 # @deprecated Use as_extended_json instead. def as_json(*args) as_extended_json end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash ] The extended json representation. def as_extended_json(**options) { EXTENDED_JSON_KEY => to_s } end # Check equality of the decimal128 object with another object. # # @example Check if the decimal128 object is equal to the other. # decimal == other # # @param [ Object ] other The object to check against. # # @return [ true, false ] If the objects are equal. # # @since 4.2.0 def ==(other) return false unless other.is_a?(Decimal128) @high == other.instance_variable_get(:@high) && @low == other.instance_variable_get(:@low) end alias :eql? :== def <=>(other) to_big_decimal <=> case other when Decimal128 other.to_big_decimal else other end end # Create a new Decimal128 from a string or a BigDecimal instance. # # @example Create a Decimal128 from a BigDecimal. # Decimal128.new(big_decimal) # # @param [ String, BigDecimal ] object The BigDecimal or String to use for # instantiating a Decimal128. # # @raise [ InvalidArgument ] When argument is not a String or BigDecimal. # # @since 4.2.0 def initialize(object) if object.is_a?(String) set_bits(*Builder::FromString.new(object).bits) elsif object.is_a?(BigDecimal) set_bits(*Builder::FromBigDecimal.new(object).bits) else raise InvalidArgument.new end end # Get the decimal128 as its raw BSON data. # # @example Get the raw bson bytes in a buffer. # decimal.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 4.2.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_decimal128(@low, @high) end # Get the hash value for the decimal128. # # @example Get the hash value. # decimal.hash # # @return [ Integer ] The hash value. # # @since 4.2.0 def hash num = @high << 64 num |= @low num.hash end # Get a nice string for use with object inspection. # # @example Inspect the decimal128 object. # decimal128.inspect # # @return [ String ] The decimal as a string. # # @since 4.2.0 def inspect "BSON::Decimal128('#{to_s}')" end # Get the string representation of the decimal128. # # @example Get the decimal128 as a string. # decimal128.to_s # # @return [ String ] The decimal128 as a string. # # @since 4.2.0 def to_s @string ||= Builder::ToString.new(self).string end alias :to_str :to_s # Get a Ruby BigDecimal object corresponding to this Decimal128. # Note that, when converting to a Ruby BigDecimal, non-zero significant digits # are preserved but trailing zeroes may be lost. # See the following example: # # @example # decimal128 = BSON::Decimal128.new("0.200") # => BSON::Decimal128('0.200') # big_decimal = decimal128.to_big_decimal # => # # big_decimal.to_s # => "0.2E0" # # Note that the the BSON::Decimal128 object can represent -NaN, sNaN, # and -sNaN while Ruby's BigDecimal cannot. # # @return [ BigDecimal ] The decimal as a BigDecimal. # # @since 4.2.0 def to_big_decimal @big_decimal ||= BigDecimal(to_s) end private def set_bits(low, high) @low = low @high = high end class << self # Deserialize the decimal128 from raw BSON bytes. # # @example Get the decimal128 from BSON. # Decimal128.from_bson(bson) # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ BSON::Decimal128 ] The decimal object. # # @since 4.2.0 def from_bson(buffer, **options) from_bits(*buffer.get_decimal128_bytes.unpack('Q<*')) end # Instantiate a Decimal128 from a string. # # @example Create a Decimal128 from a string. # BSON::Decimal128.from_string("1.05E+3") # # @param [ String ] string The string to parse. # # @raise [ BSON::Decimal128::InvalidString ] If the provided string is invalid. # # @return [ BSON::Decimal128 ] The new decimal128. # # @since 4.2.0 def from_string(string) from_bits(*Builder::FromString.new(string).bits) end # Instantiate a Decimal128 from high and low bits. # # @example Create a Decimal128 from high and low bits. # BSON::Decimal128.from_bits(high, low) # # @param [ Integer ] high The high order bits. # @param [ Integer ] low The low order bits. # # @return [ BSON::Decimal128 ] The new decimal128. # # @since 4.2.0 def from_bits(low, high) decimal = allocate decimal.send(:set_bits, low, high) decimal end end # Raised when trying to create a Decimal128 from an object that is neither a String nor a BigDecimal. # # @api private # # @since 4.2.0 class InvalidArgument < ArgumentError # The custom error message for this error. # # @since 4.2.0 MESSAGE = 'A Decimal128 can only be created from a String or BigDecimal.' # Get the custom error message for the exception. # # @example Get the message. # error.message # # @return [ String ] The error message. # # @since 4.2.0 def message MESSAGE end end # Raised when trying to create a Decimal128 from a string with # an invalid format. # # @api private # # @since 4.2.0 class InvalidString < RuntimeError # The custom error message for this error. # # @since 4.2.0 MESSAGE = 'Invalid string format for creating a Decimal128 object.' # Get the custom error message for the exception. # # @example Get the message. # error.message # # @return [ String ] The error message. # # @since 4.2.0 def message MESSAGE end end # Raised when the exponent is outside the valid range. # # @since 4.2.0 class InvalidRange < RuntimeError # The custom error message for this error. # # @since 4.2.0 # @deprecated MESSAGE = 'Value out of range for Decimal128 representation.' # Get the custom error message for the exception. # # @example Get the message. # error.message # # @return [ String ] The error message. # # @since 4.2.0 def message MESSAGE end end # Raised when the significand provided is outside the valid range. # # @note This class derives from InvalidRange for backwards compatibility, # however when RUBY-1806 is implemented it should be changed to derive # from the base BSON exception class. class UnrepresentablePrecision < InvalidRange # Get the custom error message for the exception. # # @return [ String ] The error message. def message 'The value contains too much precision for Decimal128 representation' end end Registry.register(BSON_TYPE, self) end end bson-ruby-4.15.0/lib/bson/decimal128/000077500000000000000000000000001423026727100170655ustar00rootroot00000000000000bson-ruby-4.15.0/lib/bson/decimal128/builder.rb000066400000000000000000000327631423026727100210530ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2016-2020 MongoDB Inc. # # 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. module BSON class Decimal128 # Helper module for parsing String, Integer, Float, BigDecimal, and Decimal128 # objects into other objects. # # @api private # # @since 4.2.0 module Builder # Infinity mask. # # @since 4.2.0 INFINITY_MASK = 0x7800000000000000 # NaN mask. # # @since 4.2.0 NAN_MASK = 0x7c00000000000000 # SNaN mask. # # @since 4.2.0 SNAN_MASK = (1 << 57) # Signed bit mask. # # @since 4.2.0 SIGN_BIT_MASK = (1 << 63) # The two highest bits of the 64 high order bits. # # @since 4.2.0 TWO_HIGHEST_BITS_SET = (3 << 61) extend self # Convert parts representing a Decimal128 into the corresponding bits. # # @param [ Integer ] significand The significand. # @param [ Integer ] exponent The exponent. # @param [ true, false ] is_negative Whether the value is negative. # # @return [ Array ] Tuple of the low and high bits. # # @since 4.2.0 def parts_to_bits(significand, exponent, is_negative) validate_range!(exponent, significand) exponent = exponent + Decimal128::EXPONENT_OFFSET high = significand >> 64 low = (high << 64) ^ significand if high >> 49 == 1 high = high & 0x7fffffffffff high |= TWO_HIGHEST_BITS_SET high |= (exponent & 0x3fff) << 47 else high |= exponent << 49 end if is_negative high |= SIGN_BIT_MASK end [ low, high ] end private def validate_range!(exponent, significand) unless valid_exponent?(exponent) raise Decimal128::InvalidRange.new end unless valid_significand?(significand) raise Decimal128::UnrepresentablePrecision.new end end def valid_significand?(significand) significand.to_s.length <= Decimal128::MAX_DIGITS_OF_PRECISION end def valid_exponent?(exponent) exponent <= Decimal128::MAX_EXPONENT && exponent >= Decimal128::MIN_EXPONENT end # Helper class for parsing a String into Decimal128 high and low bits. # # @api private # # @since 4.2.0 class FromString # Regex matching a string representing NaN. # # @return [ Regex ] A regex matching a NaN string. # # @since 4.2.0 NAN_REGEX = /^(\-)?(S)?NaN$/i # Regex matching a string representing positive or negative Infinity. # # @return [ Regex ] A regex matching a positive or negative Infinity string. # # @since 4.2.0 INFINITY_REGEX = /^(\+|\-)?Inf(inity)?$/i # Regex for the fraction, including leading zeros. # # @return [ Regex ] The regex for matching the fraction, # including leading zeros. # # @since 4.2.0 SIGNIFICAND_WITH_LEADING_ZEROS_REGEX = /(0*)(\d+)/ # Regex for separating a negative sign from the significands. # # @return [ Regex ] The regex for separating a sign from significands. # # @since 4.2.0 SIGN_AND_DIGITS_REGEX = /^(\-)?(\S+)/ # Regex matching a scientific exponent. # # @return [ Regex ] A regex matching E, e, E+, e+. # # @since 4.2.0 SCIENTIFIC_EXPONENT_REGEX = /E\+?/i # Regex for capturing trailing zeros. # # @since 4.2.0 TRAILING_ZEROS_REGEX = /[1-9]*(0+)$/ # Regex for a valid decimal128 string format. # # @return [ Regex ] The regex for a valid decimal128 string. # # @since 4.2.0 VALID_DECIMAL128_STRING_REGEX = /^[\-\+]?(\d+(\.\d*)?|\.\d+)(E[\-\+]?\d+)?$/i # Initialize the FromString Builder object. # # @example Create the FromString builder. # Builder::FromString.new(string) # # @param [ String ] string The string to create a Decimal128 from. # # @since 4.2.0 def initialize(string) @string = string end # Get the bits representing the Decimal128 that the string corresponds to. # # @example Get the bits for the Decimal128 object created from the string. # builder.bits # # @return [ Array ] Tuple of the low and high bits. # # @since 4.2.0 def bits if special? to_special_bits else validate_format! to_bits end end private def to_bits original, sign, digits_str = SIGN_AND_DIGITS_REGEX.match(@string).to_a digits, e, scientific_exp = digits_str.partition(SCIENTIFIC_EXPONENT_REGEX) before_decimal, decimal, after_decimal = digits.partition('.') significand_str = before_decimal << after_decimal significand_str = SIGNIFICAND_WITH_LEADING_ZEROS_REGEX.match(significand_str).to_a[2] exponent = -(after_decimal.length) exponent = exponent + scientific_exp.to_i exponent, significand_str = round_exact(exponent, significand_str) exponent, significand_str = clamp(exponent, significand_str) Builder.parts_to_bits(significand_str.to_i, exponent, sign == '-') end def round_exact(exponent, significand) if exponent < Decimal128::MIN_EXPONENT if significand.to_i == 0 round = Decimal128::MIN_EXPONENT - exponent exponent += round elsif trailing_zeros = TRAILING_ZEROS_REGEX.match(significand) round = [ (Decimal128::MIN_EXPONENT - exponent), trailing_zeros[1].size ].min significand = significand[0...-round] exponent += round end elsif significand.length > Decimal128::MAX_DIGITS_OF_PRECISION trailing_zeros = TRAILING_ZEROS_REGEX.match(significand) if trailing_zeros round = [ trailing_zeros[1].size, (significand.length - Decimal128::MAX_DIGITS_OF_PRECISION), (Decimal128::MAX_EXPONENT - exponent)].min significand = significand[0...-round] exponent += round end end [ exponent, significand ] end def clamp(exponent, significand) if exponent > Decimal128::MAX_EXPONENT if significand.to_i == 0 adjust = exponent - Decimal128::MAX_EXPONENT significand = '0' else adjust = [ (exponent - Decimal128::MAX_EXPONENT), Decimal128::MAX_DIGITS_OF_PRECISION - significand.length ].min significand << '0'* adjust end exponent -= adjust end [ exponent, significand ] end def to_special_bits high = 0 if match = NAN_REGEX.match(@string) high = NAN_MASK high = high | SIGN_BIT_MASK if match[1] high = high | SNAN_MASK if match[2] elsif match = INFINITY_REGEX.match(@string) high = INFINITY_MASK high = high | SIGN_BIT_MASK if match[1] == '-' end [ 0, high ] end def special? @string =~ NAN_REGEX || @string =~ INFINITY_REGEX end def validate_format! raise BSON::Decimal128::InvalidString.new unless @string =~ VALID_DECIMAL128_STRING_REGEX end end # Helper class for parsing a BigDecimal into Decimal128 high and low bits. # # @api private # # @since 4.2.0 class FromBigDecimal # Initialize the FromBigDecimal Builder object. # # @example Create the FromBigDecimal builder. # Builder::FromBigDecimal.new(big_decimal) # # @param [ BigDecimal ] big_decimal The big decimal object to # create a Decimal128 from. # # @since 4.2.0 def initialize(big_decimal) @big_decimal = big_decimal end # Get the bits representing the Decimal128 that the big decimal corresponds to. # # @example Get the bits for the Decimal128 object created from the big decimal. # builder.bits # # @return [ Array ] Tuple of the low and high bits. # # @since 4.2.0 def bits if special? to_special_bits else to_bits end end private def to_special_bits case @big_decimal.sign when ::BigDecimal::SIGN_POSITIVE_INFINITE high = INFINITY_MASK when ::BigDecimal::SIGN_NEGATIVE_INFINITE high = INFINITY_MASK | SIGN_BIT_MASK when ::BigDecimal::SIGN_NaN high = NAN_MASK end [ 0, high ] end def to_bits sign, significand_str, base, exp = @big_decimal.split exponent = @big_decimal.zero? ? 0 : exp - significand_str.length is_negative = (sign == ::BigDecimal::SIGN_NEGATIVE_FINITE || sign == ::BigDecimal::SIGN_NEGATIVE_ZERO) Builder.parts_to_bits(significand_str.to_i, exponent, is_negative) end def special? @big_decimal.infinite? || @big_decimal.nan? end end # Helper class for getting a String representation of a Decimal128 object. # # @api private # # @since 4.2.0 class ToString # String representing a NaN value. # # @return [ String ] The string representing NaN. # # @since 4.2.0 NAN_STRING = 'NaN' # String representing an Infinity value. # # @return [ String ] The string representing Infinity. # # @since 4.2.0 INFINITY_STRING = 'Infinity' # Initialize the FromBigDecimal Builder object. # # @example Create the ToString builder. # Builder::ToString.new(big_decimal) # # @param [ Decimal128 ] decimal128 The decimal128 object to # create a String from. # # @since 4.2.0 def initialize(decimal128) @decimal128 = decimal128 end # Get the string representing the Decimal128 object. # # @example Get a string representing the decimal128. # builder.string # # @return [ String ] The string representing the decimal128 object. # # @note The returned string may be frozen. # # @since 4.2.0 def string return NAN_STRING if nan? str = infinity? ? INFINITY_STRING : create_string negative? ? "-#{str}" : str end private def create_string if use_scientific_notation? exp_pos_sign = exponent < 0 ? '' : '+' if significand.length > 1 str = "#{significand[0]}.#{significand[1..-1]}E#{exp_pos_sign}#{scientific_exponent}" else str = "#{significand}E#{exp_pos_sign}#{scientific_exponent}" end elsif exponent < 0 if significand.length > exponent.abs decimal_point_index = significand.length - exponent.abs str = "#{significand[0..decimal_point_index-1]}.#{significand[decimal_point_index..-1]}" else left_zero_pad = (exponent + significand.length).abs str = "0.#{'0' * left_zero_pad}#{significand}" end end str || significand end def scientific_exponent @scientific_exponent ||= (significand.length - 1) + exponent end def use_scientific_notation? exponent > 0 || scientific_exponent < -6 end def exponent @exponent ||= two_highest_bits_set? ? ((high_bits & 0x1fffe00000000000) >> 47) - Decimal128::EXPONENT_OFFSET : ((high_bits & 0x7fff800000000000) >> 49) - Decimal128::EXPONENT_OFFSET end def significand @significand ||= two_highest_bits_set? ? '0' : bits_to_significand.to_s end def bits_to_significand significand = high_bits & 0x1ffffffffffff significand = significand << 64 significand |= low_bits end def two_highest_bits_set? high_bits & TWO_HIGHEST_BITS_SET == TWO_HIGHEST_BITS_SET end def nan? high_bits & NAN_MASK == NAN_MASK end def negative? high_bits & SIGN_BIT_MASK == SIGN_BIT_MASK end def infinity? high_bits & INFINITY_MASK == INFINITY_MASK end def high_bits @decimal128.instance_variable_get(:@high) end def low_bits @decimal128.instance_variable_get(:@low) end end end end endbson-ruby-4.15.0/lib/bson/document.rb000066400000000000000000000264061423026727100174070ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "yaml" # Since we have a custom bsondoc type for yaml serialization, we need # to ensure that it's properly deserialized when parsed. # # @since 2.0.0 YAML.add_builtin_type("bsondoc") do |type, value| BSON::Document[value.map{ |val| val.to_a.first }] end module BSON # This module provides behaviour for serializing and deserializing entire # BSON documents, according to the BSON specification. # # @note The specification is: document ::= int32 e_list "\x00" # # @see http://bsonspec.org/#/specification # # @since 2.0.0 class Document < ::Hash # Get a value from the document for the provided key. Can use string or # symbol access, with string access being the faster of the two. # # @overload fetch(key) # Returns a value from the hash for the given key. If the key does # not exist, raises KeyError exception. # # @overload fetch(key, default) # Returns a value from the hash for the given key. If the key does not # exist, returns *default*. # # @overload fetch(key, &block) # Returns a value from the hash for the given key. If the key does not # exist, returns the value of the block called with the key. # # @example Get an element for the key. # document.fetch("field") # # @example Get an element for the key by symbol with a default. # document.fetch(:field, 'foo') # # @example Get an element for the key by symbol with a block default. # document.fetch(:field) { |key| key.upcase } # # @param [ String, Symbol ] key The key to look up. # @param [ Object ] default Returned value if key does not exist. # @yield [key] Block returning default value for the given key. # # @return [ Object ] The found value. Raises KeyError if none found. # # @since 4.4.0 def fetch(key, *args, &block) key = convert_key(key) super(key, *args, &block) end # Get a value from the document for the provided key. Can use string or # symbol access, with string access being the faster of the two. # # @example Get an element for the key. # document["field"] # # @example Get an element for the key by symbol. # document[:field] # # @param [ String, Symbol ] key The key to look up. # # @return [ Object ] The found value, or nil if none found. # # @since 2.0.0 def [](key) super(convert_key(key)) end # Stores a key-value pair in the current document. # # Since BSON documents provide deep indifferent access (both strings and # symbols are accepted as keys, recursively), the value may be converted # to facilitate indifferent access. This conversion is performed for # built-in Array and Hash classes, and other classes can override # +to_bson_normalized_value+ method to provide custom conversion logic. # For example: # # doc = BSON::Document.new # doc[:a] = {b: {c: 'd'}} # doc['a']['b']['c'] # # => "d" # # Note that due to this conversion, the object that is stored in the # receiver Document may be different from the object supplied as the # right hand side of the assignment. In Ruby, the result of assignment # is the right hand side, not the return value of []= method. # Because of this, modifying the result of assignment generally does not # work as intended: # # doc = BSON::Document.new # foo = (doc[:a] = {b: {c: 'd'}}) # # foo is original Hash with symbol keys # foo['test'] = 'test' # # doc is not modified # doc # # => {"a"=>{"b"=>{"c"=>"d"}}} # # This behavior can be encountered when defaulting document contents with # []= in a method, such as: # # def foo # # @doc is a BSON::Document # @doc[:foo] ||= calculation # end # # The above method should be written as follows to allow chaining: # # def foo # # @doc is a BSON::Document # @doc[:foo] ||= calculation and @doc[:foo] # end # # @example Set a value on the document. # document[:test] = "value" # # @param [ String, Symbol ] key The key to update. # @param [ Object ] value The value to update. # # @return [ Object ] The updated value. # # @since 3.0.0 def []=(key, value) super(convert_key(key), convert_value(value)) end # Returns true if the given key is present in the document. Will normalize # symbol keys into strings. # # @example Test if a key exists using a symbol # document.has_key?(:test) # # @param [ Object ] key The key to check for. # # @return [ true, false] # # @since 4.0.0 def has_key?(key) super(convert_key(key)) end alias :include? :has_key? alias :key? :has_key? alias :member? :has_key? # Returns true if the given value is present in the document. Will normalize # symbols into strings. # # @example Test if a key exists using a symbol # document.has_value?(:test) # # @param [ Object ] value THe value to check for. # # @return [ true, false] # # @since 4.0.0 def has_value?(value) super(convert_value(value)) end alias :value :has_value? # Deletes the key-value pair and returns the value from the document # whose key is equal to key. # If the key is not found, returns the default value. If the optional code # block is given and the key is not found, pass in the key and return the # result of block. # # @example Delete a key-value pair # document.delete(:test) # # @param [ Object ] key The key of the key-value pair to delete. # # @return [ Object ] # # @since 4.0.0 def delete(key, &block) super(convert_key(key), &block) end # Instantiate a new Document. Valid parameters for instantiation is a hash # only or nothing. # # @example Create the new Document. # BSON::Document.new(name: "Joe", age: 33) # # @param [ Hash ] elements The elements of the document. # # @since 3.0.0 def initialize(elements = nil) super() (elements || {}).each_pair{ |key, value| self[key] = value } end # Merge this document with another document, returning a new document in # the process. # # @example Merge with another document. # document.merge(name: "Bob") # # @param [ BSON::Document, Hash ] other The document/hash to merge with. # # @return [ BSON::Document ] The result of the merge. # # @since 3.0.0 def merge(other, &block) dup.merge!(other, &block) end # Merge this document with another document, returning the same document in # the process. # # @example Merge with another document. # document.merge(name: "Bob") # # @param [ BSON::Document, Hash ] other The document/hash to merge with. # # @return [ BSON::Document ] The result of the merge. # # @since 3.0.0 def merge!(other) other.each_pair do |key, value| value = yield(convert_key(key), self[key], convert_value(value)) if block_given? && self[key] self[key] = value end self end alias :update :merge! if instance_methods.include?(:dig) # Retrieves the value object corresponding to the each key objects repeatedly. # Will normalize symbol keys into strings. # # @example Get value from nested sub-documents, handling missing levels. # document # => { :key1 => { "key2" => "value"}} # document.dig(:key1, :key2) # => "value" # document.dig("key1", "key2") # => "value" # document.dig("foo", "key2") # => nil # # @param [ Array ] *keys Keys, which constitute a "path" to the nested value. # # @return [ Object, NilClass ] The requested value or nil. # # @since 3.0.0 def dig(*keys) super(*keys.map{|key| convert_key(key)}) end end # Slices a document to include only the given keys. # Will normalize symbol keys into strings. # (this method is backported from ActiveSupport::Hash) # # @example Get a document/hash with only the `name` and `age` fields present # document # => { _id: , :name => "John", :age => 30, :location => "Earth" } # document.slice(:name, 'age') # => { "name": "John", "age" => 30 } # document.slice('name') # => { "name" => "John" } # document.slice(:foo) # => {} # # @param [ Array ] *keys Keys, that will be kept in the resulting document # # @return [ BSON::Document ] The document with only the selected keys # # @since 4.3.1 def slice(*keys) keys.each_with_object(self.class.new) do |key, hash| if key?(key) hash[key] = self[key] end end end # Returns a new document consisting of the current document minus the # specified keys. # # The keys to be removed can be specified as either strings or symbols. # # @example Get a document/hash with only the `name` and `age` fields removed # document # => { _id: , :name => 'John', :age => 30, :location => 'Earth' } # document.except(:name, 'age') # => { _id: , location: 'Earth' } # # @param [ Array ] *keys Keys, that will be removed in the resulting document # # @return [ BSON::Document ] The document with the specified keys removed. # # @note This method is always defined, even if Hash already contains a # definition of #except, because ActiveSupport unconditionally defines # its version of #except which doesn't work for BSON::Document which # causes problems if ActiveSupport is loaded after bson-ruby is. def except(*keys) copy = dup keys.each {|key| copy.delete(key)} copy end def symbolize_keys! raise ArgumentError, 'symbolize_keys! is not supported on BSON::Document instances. Please convert the document to hash first (using #to_h), then call #symbolize_keys! on the Hash instance' end # Override the Hash implementation of to_bson_normalized_value. # # BSON::Document is already of the correct type and already provides # indifferent access to keys, hence no further conversions are necessary. # # Attempting to perform Hash's conversion on Document instances converts # DBRefs to Documents which is wrong. # # @return [ BSON::Document ] The normalized hash. def to_bson_normalized_value self end private def convert_key(key) key.to_bson_normalized_key end def convert_value(value) value.to_bson_normalized_value end end end bson-ruby-4.15.0/lib/bson/environment.rb000066400000000000000000000025741423026727100201350ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Provides static helper methods around determining what environment is # running without polluting the global namespace. # # @since 2.0.0 module Environment extend self # Determine if we are using JRuby or not. # # @example Are we running with JRuby? # Environment.jruby? # # @return [ true, false ] If JRuby is our vm. # # @since 2.0.0 def jruby? @jruby ||= defined?(JRUBY_VERSION) end # Determine if we are using Ruby version 1.9. # # @example Are we running with Ruby version 1.9? # Environment.ruby_1_9? # # @return [ true, false ] If the Ruby version is 1.9. # # @since 4.2.0 # @deprecated def ruby_1_9? @ruby_1_9 ||= RUBY_VERSION < '2.0.0' end end end bson-ruby-4.15.0/lib/bson/error.rb000066400000000000000000000020601423026727100167100ustar00rootroot00000000000000# frozen_string_literal: true module BSON # Base exception class for all BSON-related errors. # # @note Many existing exceptions raised by bson-ruby do not derive from # this base class. This will change in the next major version (5.0). class Error < StandardError # Exception raised when Extended JSON parsing fails. class ExtJSONParseError < Error end # Exception raised when decoding BSON and the data contains an # unsupported binary subtype. class UnsupportedBinarySubtype < Error end # Exception raised when BSON decoding fails. class BSONDecodeError < Error end # Exception raised when serializing an Array or Hash to BSON and an # array or hash element is of a class that does not define how to serialize # itself to BSON. class UnserializableClass < Error end # Exception raised when there is an invalid argument passed into the # constructor of regexp object. This includes when the argument contains # a null byte. class InvalidRegexpPattern < Error end end end bson-ruby-4.15.0/lib/bson/ext_json.rb000066400000000000000000000347471423026727100174310ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2019-2020 MongoDB Inc. # # 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. require 'json' module BSON # This module contains methods for parsing Extended JSON 2.0. # https://github.com/mongodb/specifications/blob/master/source/extended-json.rst module ExtJSON # Parses JSON in a string into a Ruby object tree. # # There are two strategies that this method can follow. If the canonical # strategy is used which is the default, this method returns BSON types # as much as possible. This allows the resulting object tree to be # serialized back to extended JSON or to BSON while preserving the types. # The relaxed strategy, enabled by passing {emit_relaxed: true} option, # returns native Ruby types as much as possible which makes the resulting # object tree easier to work with but may lose type information. # # Please note the following aspects of this method when emitting relaxed # object trees: # # 1. $numberInt and $numberLong inputs produce Integer instances. # 2. $regularExpression inputs produce BSON Regexp instances. This may # change in a future version of bson-ruby to produce Ruby Regexp # instances, potentially depending on regular expression options. # 3. $numberDecimal inputs produce BSON Decimal128 instances. This may # change in a future version of bson-ruby to produce Ruby BigDecimal # instances instead. # # This method accepts canonical extended JSON, relaxed extended JSON and # JSON without type information as well as a mix of the above. # # @note This method uses Ruby standard library's JSON.parse method to # perform JSON parsing. As the JSON.parse method accepts inputs other # than hashes, so does this method and therefore this method can return # objects of any type. # # @param [ String ] str The string to parse. # # @option options [ nil | :bson ] :mode Which types to emit # # @return [ Object ] Parsed object tree. module_function def parse(str, **options) parse_obj(::JSON.parse(str), **options) end # Transforms a Ruby object tree containing extended JSON type hashes # into a Ruby object tree with said hashes replaced by BSON or Ruby native # types. # # @example Convert extended JSON type hashes: # BSON::ExtJSON.parse_obj('foo' => {'$numberLong' => '42'}) # => {"foo"=>#} # # @example Convert a non-hash value: # BSON::ExtJSON.parse_obj('$numberLong' => '42') # => # # # There are two strategies that this method can follow. If the canonical # strategy is used which is the default, this method returns BSON types # as much as possible. This allows the resulting object tree to be # serialized back to extended JSON or to BSON while preserving the types. # The relaxed strategy, enabled by passing {emit_relaxed: true} option, # returns native Ruby types as much as possible which makes the resulting # object tree easier to work with but may lose type information. # # Please note the following aspects of this method when emitting relaxed # object trees: # # 1. $numberInt and $numberLong inputs produce Integer instances. # 2. $regularExpression inputs produce BSON Regexp instances. This may # change in a future version of bson-ruby to produce Ruby Regexp # instances, potentially depending on regular expression options. # 3. $numberDecimal inputs produce BSON Decimal128 instances. This may # change in a future version of bson-ruby to produce Ruby BigDecimal # instances instead. # # This method accepts object trees resulting from parsing canonical # extended JSON, relaxed extended JSON and JSON without type information # as well as a mix of the above. # # @note This method accepts any types as input, not just Hash instances. # Consequently, it can return values of any type. # # @param [ Object ] value The object tree to convert. # # @option options [ nil | :bson ] :mode Which types to emit # # @return [ Object ] Converted object tree. module_function def parse_obj(value, **options) # TODO implement :ruby and :ruby! modes unless [nil, :bson].include?(options[:mode]) raise ArgumentError, "Invalid value for :mode option: #{options[:mode].inspect}" end case value when String, TrueClass, FalseClass, NilClass, Numeric value when Hash parse_hash(value, **options) when Array value.map do |item| parse_obj(item, **options) end else raise Error::ExtJSONParseError, "Unknown value type: #{value}" end end private RESERVED_KEYS = %w( $oid $symbol $numberInt $numberLong $numberDouble $numberDecimal $binary $code $scope $timestamp $regularExpression $dbPointer $date $minKey $maxKey $undefined ).freeze RESERVED_KEYS_HASH = Hash[RESERVED_KEYS.map do |key| [key, true] end].freeze module_function def parse_hash(hash, **options) if hash.empty? return {} end if dbref?(hash) # Legacy dbref handling. # Note that according to extended json spec, only hash values (but # not the top-level BSON document itself) may be of type "dbref". # This code applies to both hash values and the hash overall; however, # since we do not have DBRef as a distinct type, applying the below # logic to top level hashes doesn't cause harm. hash = hash.dup ref = hash.delete('$ref') # $id, if present, can be anything id = hash.delete('$id') if id.is_a?(Hash) id = parse_hash(id) end # Preserve $id value as it was, do not convert either to ObjectId # or to a string. But if the value was in {'$oid' => ...} format, # the value is converted to an ObjectId instance so that # serialization to BSON later on works correctly. out = {'$ref' => ref, '$id' => id} if hash.key?('$db') # $db must always be a string, if provided out['$db'] = hash.delete('$db') end return out.update(parse_hash(hash)) end if hash.length == 1 key, value = hash.first return case key when '$oid' ObjectId.from_string(value) when '$symbol' Symbol::Raw.new(value) when '$numberInt' unless value.is_a?(String) raise Error::ExtJSONParseError, "$numberInt value is of an incorrect type: #{value}" end value.to_i when '$numberLong' unless value.is_a?(String) raise Error::ExtJSONParseError, "$numberLong value is of an incorrect type: #{value}" end value = value.to_i if options[:mode] != :bson value else Int64.new(value) end when '$numberDouble' # This handles string to double conversion as well as inf/-inf/nan unless value.is_a?(String) raise Error::ExtJSONParseError, "Invalid $numberDouble value: #{value}" end BigDecimal(value).to_f when '$numberDecimal' # TODO consider returning BigDecimal here instead of Decimal128 Decimal128.new(value) when '$binary' unless value.is_a?(Hash) raise Error::ExtJSONParseError, "Invalid $binary value: #{value}" end unless value.keys.sort == %w(base64 subType) raise Error::ExtJSONParseError, "Invalid $binary value: #{value}" end encoded_value = value['base64'] unless encoded_value.is_a?(String) raise Error::ExtJSONParseError, "Invalid base64 value in $binary: #{value}" end subtype = value['subType'] unless subtype.is_a?(String) raise Error::ExtJSONParseError, "Invalid subType value in $binary: #{value}" end create_binary(encoded_value, subtype) when '$uuid' unless /\A[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}\z/.match(value) raise Error::ExtJSONParseError, "Invalid $uuid value: #{value}" end return Binary.from_uuid(value) when '$code' unless value.is_a?(String) raise Error::ExtJSONParseError, "Invalid $code value: #{value}" end Code.new(value) when '$timestamp' unless value.keys.sort == %w(i t) raise Error::ExtJSONParseError, "Invalid $timestamp value: #{value}" end t = value['t'] unless t.is_a?(Integer) raise Error::ExtJSONParseError, "Invalid t value: #{value}" end i = value['i'] unless i.is_a?(Integer) raise Error::ExtJSONParseError, "Invalid i value: #{value}" end Timestamp.new(t, i) when '$regularExpression' unless value.keys.sort == %w(options pattern) raise Error::ExtJSONParseError, "Invalid $regularExpression value: #{value}" end # TODO consider returning Ruby regular expression object here create_regexp(value['pattern'], value['options']) when '$dbPointer' unless value.keys.sort == %w($id $ref) raise Error::ExtJSONParseError, "Invalid $dbPointer value: #{value}" end DbPointer.new(value['$ref'], parse_hash(value['$id'])) when '$date' case value when String ::Time.parse(value).utc when Hash unless value.keys.sort == %w($numberLong) raise Error::ExtJSONParseError, "Invalid value for $date: #{value}" end sec, msec = value.values.first.to_i.divmod(1000) ::Time.at(sec, msec*1000).utc else raise Error::ExtJSONParseError, "Invalid value for $date: #{value}" end when '$minKey' unless value == 1 raise Error::ExtJSONParseError, "Invalid $minKey value: #{value}" end MinKey.new when '$maxKey' unless value == 1 raise Error::ExtJSONParseError, "Invalid $maxKey value: #{value}" end MaxKey.new when '$undefined' unless value == true raise Error::ExtJSONParseError, "Invalid $undefined value: #{value}" end Undefined.new else map_hash(hash, **options) end end if hash.length == 2 sorted_keys = hash.keys.sort first_key = sorted_keys.first last_key = sorted_keys.last if first_key == '$code' unless sorted_keys == %w($code $scope) raise Error::ExtJSONParseError, "Invalid $code value: #{hash}" end unless hash['$code'].is_a?(String) raise Error::ExtJSONParseError, "Invalid $code value: #{value}" end return CodeWithScope.new(hash['$code'], map_hash(hash['$scope'])) end if first_key == '$binary' unless sorted_keys == %w($binary $type) raise Error::ExtJSONParseError, "Invalid $binary value: #{hash}" end unless hash['$binary'].is_a?(String) raise Error::ExtJSONParseError, "Invalid $binary value: #{value}" end unless hash['$type'].is_a?(String) raise Error::ExtJSONParseError, "Invalid $binary subtype: #{hash['$type']}" end return create_binary(hash['$binary'], hash['$type']) end if last_key == '$regex' unless sorted_keys == %w($options $regex) raise Error::ExtJSONParseError, "Invalid $regex value: #{hash}" end if hash['$regex'].is_a?(Hash) return { '$regex' => parse_hash(hash['$regex']), '$options' => hash['$options'] } end unless hash['$regex'].is_a?(String) raise Error::ExtJSONParseError, "Invalid $regex pattern: #{hash['$regex']}" end unless hash['$options'].is_a?(String) raise Error::ExtJSONParseError, "Invalid $regex options: #{hash['$options']}" end return create_regexp(hash['$regex'], hash['$options']) end verify_no_reserved_keys(hash, **options) end verify_no_reserved_keys(hash, **options) end module_function def verify_no_reserved_keys(hash, **options) if hash.length > RESERVED_KEYS.length if RESERVED_KEYS.any? { |key| hash.key?(key) } raise Error::ExtJSONParseError, "Hash uses reserved keys but does not match a known type: #{hash}" end else if hash.keys.any? { |key| RESERVED_KEYS_HASH.key?(key) } raise Error::ExtJSONParseError, "Hash uses reserved keys but does not match a known type: #{hash}" end end map_hash(hash, **options) end module_function def map_hash(hash, **options) ::Hash[hash.map do |key, value| if (key.is_a?(String) || key.is_a?(Symbol)) && key.to_s.include?(NULL_BYTE) raise Error::ExtJSONParseError, "Hash key cannot contain a null byte: #{key}" end [key, parse_obj(value, **options)] end] end module_function def create_binary(encoded_value, encoded_subtype) subtype = encoded_subtype.hex type = Binary::TYPES[subtype.chr] unless type # Requires https://jira.mongodb.org/browse/RUBY-2056 raise NotImplementedError, "Binary subtype #{encoded_subtype} is not currently supported" end Binary.new(Base64.decode64(encoded_value), type) end module_function def create_regexp(pattern, options) Regexp::Raw.new(pattern, options) end module_function def dbref?(hash) if db = hash.key?('$db') unless db.is_a?(String) return false end end return hash['$ref']&.is_a?(String) && hash.key?('$id') end end end bson-ruby-4.15.0/lib/bson/false_class.rb000066400000000000000000000033531423026727100200440ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding and decoding false values to and from # raw bytes as specified by the BSON spec. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 module FalseClass # A false value in the BSON spec is 0x00. # # @since 2.0.0 FALSE_BYTE = String.new(0.chr, encoding: BINARY).freeze # The BSON type for false values is the general boolean type of 0x08. # # @example Get the bson type. # false.bson_type # # @return [ String ] The character 0x08. # # @since 2.0.0 def bson_type Boolean::BSON_TYPE end # Get the false boolean as encoded BSON. # # @example Get the false boolean as encoded BSON. # false.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_byte(FALSE_BYTE) end end # Enrich the core FalseClass class with this module. # # @since 2.0.0 ::FalseClass.send(:include, FalseClass) end bson-ruby-4.15.0/lib/bson/float.rb000066400000000000000000000067431423026727100167000ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding and decoding floating point values # to and from raw bytes as specified by the BSON spec. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 module Float # A floating point is type 0x01 in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(1.chr, encoding: BINARY).freeze # The pack directive is for 8 byte floating points. # # @since 2.0.0 PACK = "E" # Get the floating point as encoded BSON. # # @example Get the floating point as encoded BSON. # 1.221311.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_double(self) end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # This method returns the float itself if relaxed representation is # requested and the value is finite, otherwise a $numberDouble hash. # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash | Float ] The extended json representation. def as_extended_json(**options) if infinite? == 1 { '$numberDouble' => 'Infinity' } elsif infinite? == -1 { '$numberDouble' => '-Infinity' } elsif nan? { '$numberDouble' => 'NaN' } elsif options[:mode] == :relaxed || options[:mode] == :legacy self elsif BSON::Environment.jruby? && abs > 1e15 # Hack to make bson corpus spec tests pass. # JRuby serializes -1.2345678901234568e+18 as # -1234567890123456770.0, which is valid but differs from MRI # serialization. Extended JSON spec does not define precise # stringification of floats. # https://jira.mongodb.org/browse/SPEC-1536 { '$numberDouble' => ('%.17g' % to_s).upcase } else { '$numberDouble' => to_s.upcase } end end module ClassMethods # Deserialize an instance of a Float from a BSON double. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ Float ] The decoded Float. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def from_bson(buffer, **options) buffer.get_double end end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, ::Float) end # Enrich the core Float class with this module. # # @since 2.0.0 ::Float.send(:include, Float) ::Float.send(:extend, Float::ClassMethods) end bson-ruby-4.15.0/lib/bson/hash.rb000066400000000000000000000123431423026727100165070ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding and decoding hashes to # and from raw bytes as specified by the BSON spec. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 module Hash # A hash, also called an embedded document, is type 0x03 in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(3.chr, encoding: BINARY).freeze # Get the hash as encoded BSON. # # @example Get the hash as encoded BSON. # { "field" => "value" }.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) if buffer.respond_to?(:put_hash) buffer.put_hash(self, validating_keys) else position = buffer.length buffer.put_int32(0) each do |field, value| unless value.respond_to?(:bson_type) raise Error::UnserializableClass, "Hash value for key '#{field}' does not define its BSON serialized type: #{value}" end buffer.put_byte(value.bson_type) key = field.to_bson_key(validating_keys) begin buffer.put_cstring(key) rescue ArgumentError => e raise ArgumentError, "Error serializing key #{key}: #{e.class}: #{e}" rescue EncodingError => e # Note this may convert exception class from a subclass of # EncodingError to EncodingError itself raise EncodingError, "Error serializing key #{key}: #{e.class}: #{e}" end value.to_bson(buffer, validating_keys) end buffer.put_byte(NULL_BYTE) buffer.replace_int32(position, buffer.length - position) end end # Converts the hash to a normalized value in a BSON document. # # @example Convert the hash to a normalized value. # hash.to_bson_normalized_value # # @return [ BSON::Document ] The normalized hash. # # @since 3.0.0 def to_bson_normalized_value Document.new(self) end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # This method recursively invokes +as_extended_json+ with the provided # options on each hash value. # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash ] This hash converted to extended json representation. def as_extended_json(**options) transform_values { |value| value.as_extended_json(**options) } end module ClassMethods # Deserialize the hash from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ Hash ] The decoded hash. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def from_bson(buffer, **options) if buffer.respond_to?(:get_hash) buffer.get_hash(**options) else hash = Document.allocate start_position = buffer.read_position expected_byte_size = buffer.get_int32 while (type = buffer.get_byte) != NULL_BYTE field = buffer.get_cstring cls = BSON::Registry.get(type, field) value = if options.empty? # Compatibility with the older Ruby driver versions which define # a DBRef class with from_bson accepting a single argument. cls.from_bson(buffer) else cls.from_bson(buffer, **options) end hash.store(field, value) end actual_byte_size = buffer.read_position - start_position if actual_byte_size != expected_byte_size raise Error::BSONDecodeError, "Expected hash to take #{expected_byte_size} bytes but it took #{actual_byte_size} bytes" end if hash['$ref'] && hash['$id'] # We're doing implicit decoding here. If the document is an invalid # dbref, we should decode it as a BSON::Document. begin hash = DBRef.new(hash) rescue ArgumentError end end hash end end end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, ::Hash) end # Enrich the core Hash class with this module. # # @since 2.0.0 ::Hash.send(:include, Hash) ::Hash.send(:extend, Hash::ClassMethods) end bson-ruby-4.15.0/lib/bson/int32.rb000066400000000000000000000075121423026727100165250ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Represents int32 type. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 class Int32 # A boolean is type 0x08 in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(16.chr, encoding: BINARY).freeze # The number of bytes constant. # # @since 4.0.0 BYTES_LENGTH = 4 # Constant for the int 32 pack directive. # # @since 2.0.0 PACK = "l<" # Deserialize an Integer from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ Integer ] The decoded Integer. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def self.from_bson(buffer, **options) buffer.get_int32 end # Instantiate a BSON Int32. # # @param [ Integer ] value The 32-bit integer. # # @see http://bsonspec.org/#/specification # # @since 4.2.0 def initialize(value) if value.is_a?(self.class) @value = value.value return end unless value.bson_int32? raise RangeError.new("#{value} cannot be stored in 32 bits") end @value = value.freeze end # Returns the value of this Int32. # # @return [ Integer ] The integer value. attr_reader :value # Append the integer as encoded BSON to a ByteBuffer. # # @example Encoded the integer and append to a ByteBuffer. # int32.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded integer. # # @see http://bsonspec.org/#/specification # # @since 4.2.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_int32(value) end # Convert the integer to a BSON string key. # # @example Convert the integer to a BSON key string. # int.to_bson_key # # @param [ true, false ] validating_keys If BSON should validate the key. # # @return [ String ] The string key. # # @since 4.2.0 def to_bson_key(validating_keys = Config.validating_keys?) value end # Check equality of the int32 with another object. # # @param [ Object ] other The object to check against. # # @return [ true, false ] If the objects are equal. # # @since 4.4.0 def ==(other) return false unless other.is_a?(Int32) value == other.value end alias :eql? :== alias :=== :== # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # This method returns the integer value if relaxed representation is # requested, otherwise a $numberInt hash. # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash | Integer ] The extended json representation. def as_extended_json(**options) if options[:mode] == :relaxed || options[:mode] == :legacy value else {'$numberInt' => value.to_s} end end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, self) end end bson-ruby-4.15.0/lib/bson/int64.rb000066400000000000000000000075461423026727100165410ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Represents int64 type. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 class Int64 # A boolean is type 0x08 in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(18.chr, encoding: BINARY).freeze # Constant for the int 64 pack directive. # # @since 2.0.0 PACK = "q<" # Deserialize an Integer from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ Integer | BSON::Int64 ] The decoded Integer. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def self.from_bson(buffer, **options) value = buffer.get_int64 if options[:mode] == :bson new(value) else value end end # Instantiate a BSON Int64. # # @param [ Integer ] value The 64-bit integer. # # @see http://bsonspec.org/#/specification # # @since 4.2.0 def initialize(value) if value.is_a?(self.class) @value = value.value return end unless value.bson_int64? raise RangeError.new("#{value} cannot be stored in 64 bits") end @value = value.freeze end # Returns the value of this Int64. # # @return [ Integer ] The integer value. attr_reader :value # Append the integer as encoded BSON to a ByteBuffer. # # @example Encoded the integer and append to a ByteBuffer. # int64.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded integer. # # @see http://bsonspec.org/#/specification # # @since 4.2.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_int64(value) end # Convert the integer to a BSON string key. # # @example Convert the integer to a BSON key string. # int.to_bson_key # # @param [ true, false ] validating_keys If BSON should validate the key. # # @return [ String ] The string key. # # @since 4.2.0 def to_bson_key(validating_keys = Config.validating_keys?) value end # Check equality of the int64 with another object. # # @param [ Object ] other The object to check against. # # @return [ true, false ] If the objects are equal. # # @since 4.4.0 def ==(other) return false unless other.is_a?(Int64) value == other.value end alias :eql? :== alias :=== :== # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # This method returns the integer value if relaxed representation is # requested, otherwise a $numberLong hash. # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash | Integer ] The extended json representation. def as_extended_json(**options) if options[:mode] == :relaxed || options[:mode] == :legacy value else {'$numberLong' => value.to_s} end end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, self) end end bson-ruby-4.15.0/lib/bson/integer.rb000066400000000000000000000141061423026727100172200ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding and decoding integer values to and from # raw bytes as specified by the BSON spec. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 module Integer # The maximum 32 bit integer value. # # @since 2.0.0 MAX_32BIT = (1 << 31) - 1 # The maximum 64 bit integer value. # # @since 2.0.0 MAX_64BIT = (1 << 63) - 1 # The minimum 32 bit integer value. # # @since 2.0.0 MIN_32BIT = -(1 << 31) # The minimum 64 bit integer value. # # @since 2.0.0 MIN_64BIT = -(1 << 63) # The BSON index size. # # @since 2.0.0 BSON_INDEX_SIZE = 1024 # A hash of index values for array optimization. # # @since 2.0.0 BSON_ARRAY_INDEXES = ::Array.new(BSON_INDEX_SIZE) do |i| (i.to_s.b << NULL_BYTE).freeze end.freeze # Is this integer a valid BSON 32 bit value? # # @example Is the integer a valid 32 bit value? # 1024.bson_int32? # # @return [ true, false ] If the integer is 32 bit. # # @since 2.0.0 def bson_int32? (MIN_32BIT <= self) && (self <= MAX_32BIT) end # Is this integer a valid BSON 64 bit value? # # @example Is the integer a valid 64 bit value? # 1024.bson_int64? # # @return [ true, false ] If the integer is 64 bit. # # @since 2.0.0 def bson_int64? (MIN_64BIT <= self) && (self <= MAX_64BIT) end # Get the BSON type for this integer. Will depend on whether the integer # is 32 bit or 64 bit. # # @example Get the BSON type for the integer. # 1024.bson_type # # @return [ String ] The single byte BSON type. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def bson_type bson_int32? ? Int32::BSON_TYPE : (bson_int64? ? Int64::BSON_TYPE : out_of_range!) end # Get the integer as encoded BSON. # # @example Get the integer as encoded BSON. # 1024.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) if bson_int32? buffer.put_int32(self) elsif bson_int64? buffer.put_int64(self) else out_of_range! end end # Convert the integer to a 32 bit (4 bytes) raw bytes string. # # @example Convert the integer to it's 32 bit bytes. # 1024.to_bson_int32 # # @param [ String ] encoded The string to encode to. # # @return [ String ] The encoded string. # # @since 2.0.0 def to_bson_int32(encoded) append_bson_int32(encoded) end # Convert the integer to a 64 bit (8 bytes) raw bytes string. # # @example Convert the integer to it's 64 bit bytes. # 1024.to_bson_int64 # # @param [ String ] encoded The string to encode to. # # @return [ String ] The encoded string. # # @since 2.0.0 def to_bson_int64(encoded) append_bson_int32(encoded) encoded << ((self >> 32) & 255) encoded << ((self >> 40) & 255) encoded << ((self >> 48) & 255) encoded << ((self >> 56) & 255) end # Convert the integer to a BSON string key. # # @example Convert the integer to a BSON key string. # 1.to_bson_key # # @param [ true, false ] validating_keys If BSON should validate the key. # # @return [ String ] The string key. # # @since 2.0.0 def to_bson_key(validating_keys = Config.validating_keys?) self end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # This method returns the integer itself if relaxed representation is # requested, otherwise a $numberInt hash if the value fits in 32 bits # and a $numberLong otherwise. Regardless of which representation is # requested, a value that does not fit in 64 bits raises RangeError. # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash | Integer ] The extended json representation. def as_extended_json(**options) # The behavior of native integers' serialization to extended json is # not specified. Following our bson serialization logic in this file, # produce explicit $numberInt or $numberLong, choosing $numberInt if # the integer fits in 32 bits. In Ruby integers can be arbitrarily # big; integers that do not fit into 64 bits raise an error as we do not # want to silently perform an effective type conversion of integer -> # decimal. unless bson_int64? raise RangeError, "Integer #{self} is too big to be represented as a MongoDB integer" end if options[:mode] == :relaxed || options[:mode] == :legacy self elsif bson_int32? {'$numberInt' => to_s} else {'$numberLong' => to_s} end end private def append_bson_int32(encoded) encoded << (self & 255) encoded << ((self >> 8) & 255) encoded << ((self >> 16) & 255) encoded << ((self >> 24) & 255) end def out_of_range! raise RangeError.new("#{self} is not a valid 8 byte integer value.") end end # Enrich the core Integer class with this module. # # @since 2.0.0 ::Integer.send(:include, Integer) end bson-ruby-4.15.0/lib/bson/json.rb000066400000000000000000000021361423026727100165340ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Provides common behaviour for JSON serialization of objects. # # @since 2.0.0 module JSON # Converting an object to JSON simply gets it's hash representation via # as_json, then converts it to a string. # # @example Convert the object to JSON # object.to_json # # @note All types must implement as_json. # # @return [ String ] The object as JSON. # # @since 2.0.0 def to_json(*args) as_json.to_json(*args) end end end bson-ruby-4.15.0/lib/bson/max_key.rb000066400000000000000000000044221423026727100172200ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Represents a $maxKey type, which compares less than any other value in the # specification. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 class MaxKey include Comparable include JSON include Specialized # A $maxKey is type 0x7F in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(127.chr, encoding: BINARY).freeze # Constant for always evaluating greater in a comparison. # # @since 2.0.0 GREATER = 1 # When comparing a max key with any other object, the max key will always # be greater. # # @example Compare with another object. # max_key <=> 1000 # # @param [ Object ] other The object to compare against. # # @return [ Integer ] Always 1. # # @since 2.0.0 def <=>(other) GREATER end # Get the max key as JSON hash data. # # @example Get the max key as a JSON hash. # max_key.as_json # # @return [ Hash ] The max key as a JSON hash. # # @since 2.0.0 # @deprecated Use as_extended_json instead. def as_json(*args) as_extended_json end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash ] The extended json representation. def as_extended_json(**options) { "$maxKey" => 1 } end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, self) end end bson-ruby-4.15.0/lib/bson/min_key.rb000066400000000000000000000044201423026727100172140ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Represents a $minKey type, which compares less than any other value in the # specification. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 class MinKey include Comparable include JSON include Specialized # A $minKey is type 0xFF in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(255.chr, encoding: BINARY).freeze # Constant for always evaluating lesser in a comparison. # # @since 2.0.0 LESSER = -1 # When comparing a min key with any other object, the min key will always # be lesser. # # @example Compare with another object. # min_key <=> 1000 # # @param [ Object ] other The object to compare against. # # @return [ Integer ] Always -1. # # @since 2.0.0 def <=>(other) LESSER end # Get the min key as JSON hash data. # # @example Get the min key as a JSON hash. # min_key.as_json # # @return [ Hash ] The min key as a JSON hash. # # @since 2.0.0 # @deprecated Use as_extended_json instead. def as_json(*args) as_extended_json end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash ] The extended json representation. def as_extended_json(**options) { "$minKey" => 1 } end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, self) end end bson-ruby-4.15.0/lib/bson/nil_class.rb000066400000000000000000000032411423026727100175300ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding and decoding nil values to and from # raw bytes as specified by the BSON spec. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 module NilClass include Specialized # A nil is type 0x0A in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(10.chr, encoding: BINARY).freeze module ClassMethods # Deserialize NilClass from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ nil ] The decoded nil value. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def from_bson(buffer, **options) nil end end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, ::NilClass) end # Enrich the core NilClass class with this module. # # @since 2.0.0 ::NilClass.send(:include, NilClass) ::NilClass.send(:extend, NilClass::ClassMethods) end bson-ruby-4.15.0/lib/bson/object.rb000066400000000000000000000064551423026727100170410ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for all Ruby objects. # # @since 2.2.4 module Object # Objects that don't override this method will raise an error when trying # to use them as keys in a BSON document. This is only overridden in String # and Symbol. # # @example Convert the object to a BSON key. # object.to_bson_key # # @raise [ InvalidKey ] Always raises an exception. # # @see http://bsonspec.org/#/specification # # @since 2.2.4 def to_bson_key(validating_keys = Config.validating_keys?) raise InvalidKey.new(self) end # Converts the object to a normalized key in a BSON document. # # @example Convert the object to a normalized key. # object.to_bson_normalized_key # # @return [ Object ] self. # # @since 3.0.0 def to_bson_normalized_key self end # Converts the object to a normalized value in a BSON document. # # @example Convert the object to a normalized value. # object.to_bson_normalized_value # # @return [ Object ] self. # # @since 3.0.0 def to_bson_normalized_value self end # Serializes this object to Extended JSON # (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # Subclasses should override +as_extended_json+ rather than this method. # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ String ] The extended json serialization. def to_extended_json(**options) as_extended_json(**options).to_json end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # Subclasses should override this method to provide custom serialization # to Extended JSON. # # @option options [ true | false ] :relaxed Whether to produce relaxed # extended JSON representation. # # @return [ Object ] The extended json representation. def as_extended_json(**options) self end end # Raised when trying to serialize an object into a key. # # @since 2.2.4 class InvalidKey < RuntimeError # Instantiate the exception. # # @example Instantiate the exception. # BSON::Object::InvalidKey.new(object) # # @param [ Object ] object The object that was meant for the key. # # @since 2.2.4 def initialize(object) super("#{object.class} instances are not allowed as keys in a BSON document.") end end # Enrich the core Object class with this module. # # @since 2.2.4 ::Object.send(:include, Object) end bson-ruby-4.15.0/lib/bson/object_id.rb000066400000000000000000000264631423026727100175160ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "digest/md5" require "socket" require "thread" module BSON # Represents object_id data. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 class ObjectId include Comparable include JSON # A object_id is type 0x07 in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(7.chr, encoding: BINARY).freeze # Check equality of the object id with another object. # # @example Check if the object id is equal to the other. # object_id == other # # @param [ Object ] other The object to check against. # # @return [ true, false ] If the objects are equal. # # @since 2.0.0 def ==(other) return false unless other.is_a?(ObjectId) generate_data == other.send(:generate_data) end alias :eql? :== # Check case equality on the object id. # # @example Check case equality. # object_id === other # # @param [ Object ] other The object to check against. # # @return [ true, false ] If the objects are equal in a case. # # @since 2.0.0 def ===(other) return to_str === other.to_str if other.respond_to?(:to_str) super end # Return the object id as a JSON hash representation. # # @example Get the object id as JSON. # object_id.as_json # # @return [ Hash ] The object id as a JSON hash. # # @since 2.0.0 # @deprecated Use as_extended_json instead. def as_json(*args) as_extended_json end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash ] The extended json representation. def as_extended_json(**options) { "$oid" => to_s } end # Compare this object id with another object for use in sorting. # # @example Compare the object id with the other object. # object <=> other # # @param [ Object ] other The object to compare to. # # @return [ Integer ] The result of the comparison. # # @since 2.0.0 def <=>(other) generate_data <=> other.to_bson.to_s end # Return the UTC time at which this ObjectId was generated. This may # be used instread of a created_at timestamp since this information # is always encoded in the object id. # # @example Get the generation time. # object_id.generation_time # # @return [ Time ] The time the id was generated. # # @since 2.0.0 def generation_time ::Time.at(generate_data.unpack1("N")).utc end alias :to_time :generation_time # Get the hash value for the object id. # # @example Get the hash value. # object_id.hash # # @return [ Integer ] The hash value. # # @since 2.0.0 def hash generate_data.hash end # Get a nice string for use with object inspection. # # @example Inspect the object id. # object_id.inspect # # @return [ String ] The object id in form BSON::ObjectId('id') # # @since 2.0.0 def inspect "BSON::ObjectId('#{to_s}')" end # Dump the raw bson when calling Marshal.dump. # # @example Dump the raw bson. # Marshal.dump(object_id) # # @return [ String ] The raw bson bytes. # # @since 2.0.0 def marshal_dump generate_data end # Unmarshal the data into an object id. # # @example Unmarshal the data. # Marshal.load(data) # # @param [ String ] data The raw bson bytes. # # @return [ String ] The raw bson bytes. # # @since 2.0.0 def marshal_load(data) @raw_data = data end # Get the object id as it's raw BSON data. # # @example Get the raw bson bytes. # object_id.to_bson # # @note Since Moped's BSON and MongoDB BSON before 2.0.0 have different # internal representations, we will attempt to repair the data for cases # where the object was instantiated in a non-standard way. (Like a # Marshal.load) # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_bytes(generate_data) end # Get the string representation of the object id. # # @example Get the object id as a string. # object_id.to_s # # @return [ String ] The object id as a string. # # @since 2.0.0 def to_s generate_data.to_hex_string.force_encoding(UTF8) end alias :to_str :to_s # Raised when trying to create an object id with invalid data. # # @since 2.0.0 class Invalid < RuntimeError; end private def initialize_copy(other) generate_data other.instance_variable_set(:@raw_data, @raw_data) end def generate_data repair if defined?(@data) @raw_data ||= @@generator.next_object_id end def repair @raw_data = @data.to_bson_object_id remove_instance_variable(:@data) end class << self # Deserialize the object id from raw BSON bytes. # # @example Get the object id from BSON. # ObjectId.from_bson(bson) # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ BSON::ObjectId ] The object id. # # @since 2.0.0 def from_bson(buffer, **options) from_data(buffer.get_bytes(12)) end # Create a new object id from raw bytes. # # @example Create an object id from raw bytes. # BSON::ObjectId.from_data(data) # # @param [ String ] data The raw bytes. # # @return [ ObjectId ] The new object id. # # @since 2.0.0 def from_data(data) object_id = allocate object_id.instance_variable_set(:@raw_data, data) object_id end # Create a new object id from a string. # # @example Create an object id from the string. # BSON::ObjectId.from_string(id) # # @param [ String ] string The string to create the id from. # # @raise [ BSON::ObjectId::Invalid ] If the provided string is invalid. # # @return [ BSON::ObjectId ] The new object id. # # @since 2.0.0 def from_string(string) unless legal?(string) raise Invalid.new("'#{string}' is an invalid ObjectId.") end from_data([ string ].pack("H*")) end # Create a new object id from a time. # # @example Create an object id from a time. # BSON::ObjectId.from_time(time) # # @example Create an object id from a time, ensuring uniqueness. # BSON::ObjectId.from_time(time, unique: true) # # @param [ Time ] time The time to generate from. # @param [ Hash ] options The options. # # @option options [ true, false ] :unique Whether the id should be # unique. # # @return [ ObjectId ] The new object id. # # @since 2.0.0 def from_time(time, options = {}) from_data(options[:unique] ? @@generator.next_object_id(time.to_i) : [ time.to_i ].pack("Nx8")) end # Determine if the provided string is a legal object id. # # @example Is the string a legal object id? # BSON::ObjectId.legal?(string) # # @param [ String ] string The string to check. # # @return [ true, false ] If the string is legal. # # @since 2.0.0 def legal?(string) string.to_s =~ /\A[0-9a-f]{24}\z/i ? true : false end # Executes the provided block only if the size of the provided object is # 12. Used in legacy id repairs. # # @example Execute in a repairing block. # BSON::ObjectId.repair("test") { obj } # # @param [ String, Array ] object The object to repair. # # @raise [ Invalid ] If the array is not 12 elements. # # @return [ String ] The result of the block. # # @since 2.0.0 def repair(object) if object.size == 12 block_given? ? yield(object) : object else raise Invalid.new("#{object.inspect} is not a valid object id.") end end end # Inner class that encapsulates the behaviour of actually generating each # part of the ObjectId. # # @api private # # @since 2.0.0 class Generator # @!attribute machine_id # @return [ String ] The unique machine id. # @since 2.0.0 attr_reader :machine_id # Instantiate the new object id generator. Will set the machine id once # on the initial instantiation. # # @example Instantiate the generator. # BSON::ObjectId::Generator.new # # @since 2.0.0 def initialize @counter = rand(0x1000000) @machine_id = Digest::MD5.digest(Socket.gethostname).unpack1("N") @mutex = Mutex.new end # Return object id data based on the current time, incrementing the # object id counter. Will use the provided time if not nil. # # @example Get the next object id data. # generator.next_object_id # # @param [ Time ] time The optional time to generate with. # # @return [ String ] The raw object id bytes. # # @since 2.0.0 def next_object_id(time = nil) @mutex.lock begin count = @counter = (@counter + 1) % 0xFFFFFF ensure @mutex.unlock rescue nil end generate(time || ::Time.new.to_i, count) end # Generate object id data for a given time using the provided counter. # # @example Generate the object id bytes. # generator.generate(time) # # @param [ Integer ] time The time since epoch in seconds. # @param [ Integer ] counter The optional counter. # # @return [ String ] The raw object id bytes. # # @since 2.0.0 def generate(time, counter = 0) [ time, machine_id, process_id, counter << 8 ].pack("N NX lXX NX") end private if Environment.jruby? def process_id "#{Process.pid}#{Thread.current.object_id}".hash % 0xFFFF end else def process_id Process.pid % 0xFFFF end end end # We keep one global generator for object ids. # # @since 2.0.0 @@generator = Generator.new # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, self) end end bson-ruby-4.15.0/lib/bson/open_struct.rb000066400000000000000000000032501423026727100201260ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2016-2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding OpenStruct objects using hashes # to raw bytes as specified by the BSON spec. # # @see http://bsonspec.org/#/specification # # @since 4.2.0 module OpenStruct # Get the OpenStruct as encoded BSON. # # @example Get the OpenStruct object as encoded BSON. # OpenStruct.new({ "field" => "value" }).to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 4.2.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) if Environment.ruby_1_9? marshal_dump.dup else to_h end.to_bson(buffer, validating_keys) end # The BSON type for OpenStruct objects is the Hash type of 0x03. # # @example Get the bson type. # struct.bson_type # # @return [ String ] The character 0x03. # # @since 4.2.0 def bson_type ::Hash::BSON_TYPE end end ::OpenStruct.send(:include, OpenStruct) if defined?(::OpenStruct) end bson-ruby-4.15.0/lib/bson/regexp.rb000066400000000000000000000226431423026727100170620ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding and decoding regular expression values to # and from raw bytes as specified by the BSON spec. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 module Regexp include JSON # A regular expression is type 0x0B in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(11.chr, encoding: BINARY).freeze # Extended value constant. # # @since 3.2.6 EXTENDED_VALUE = 'x' # Ignore case constant. # # @since 3.2.6 IGNORECASE_VALUE = 'i' # Multiline constant. # # @since 3.2.6 MULTILINE_VALUE = 'm' # Newline constant. # # @since 3.2.6 NEWLINE_VALUE = 's' # Ruby multiline constant. # # @since 3.2.6 # # @deprecated Will be removed in 5.0 RUBY_MULTILINE_VALUE = 'ms' # Get the regexp as JSON hash data. # # @example Get the regexp as a JSON hash. # regexp.as_json # # @return [ Hash ] The regexp as a JSON hash. # # @since 2.0.0 def as_json(*args) { "$regex" => source, "$options" => bson_options } end # Get the regular expression as encoded BSON. # # @example Get the regular expression as encoded BSON. # %r{\d+}.to_bson # # @note From the BSON spec: The first cstring is the regex pattern, # the second is the regex options string. Options are identified # by characters, which must be stored in alphabetical order. # Valid options are 'i' for case insensitive matching, # 'm' for multiline matching, 'x' for verbose mode, # 'l' to make \w, \W, etc. locale dependent, # 's' for dotall mode ('.' matches everything), # and 'u' to make \w, \W, etc. match unicode. # # @param [ BSON::ByteBuffer ] buffer The byte buffer to append to. # @param [ true, false ] validating_keys # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_cstring(source) buffer.put_cstring(bson_options) end private def bson_options # Ruby's Regexp always has BSON's equivalent of 'm' on, so always add it bson_ignorecase + MULTILINE_VALUE + bson_dotall + bson_extended end def bson_extended (options & ::Regexp::EXTENDED != 0) ? EXTENDED_VALUE : NO_VALUE end def bson_ignorecase (options & ::Regexp::IGNORECASE != 0) ? IGNORECASE_VALUE : NO_VALUE end def bson_dotall # Ruby Regexp's MULTILINE is equivalent to BSON's dotall value (options & ::Regexp::MULTILINE != 0) ? NEWLINE_VALUE : NO_VALUE end # Represents the raw values for the regular expression. # # @see https://jira.mongodb.org/browse/RUBY-698 # # @since 3.0.0 class Raw include JSON # @return [ String ] pattern The regex pattern. attr_reader :pattern # @return [ Integer ] options The options. attr_reader :options # Compile the Regular expression into the native type. # # @example Compile the regular expression. # raw.compile # # @return [ ::Regexp ] The compiled regular expression. # # @since 3.0.0 def compile @compiled ||= ::Regexp.new(pattern, options_to_int) end # Initialize the new raw regular expression. # # @example Initialize the raw regexp. # Raw.new(pattern, options) # # @param [ String ] pattern The regular expression pattern. # @param [ String, Integer ] options The options. # # @note The ability to specify options as an Integer is deprecated. # Please specify options as a String. The ability to pass options as # as Integer will be removed in version 5.0.0. # # @since 3.0.0 def initialize(pattern, options = '') if pattern.include?(NULL_BYTE) raise Error::InvalidRegexpPattern, "Regexp pattern cannot contain a null byte: #{pattern}" elsif options.is_a?(String) || options.is_a?(Symbol) if options.to_s.include?(NULL_BYTE) raise Error::InvalidRegexpPattern, "Regexp options cannot contain a null byte: #{options}" end elsif !options.is_a?(Integer) raise ArgumentError, "Regexp options must be a String, Symbol, or Integer" end @pattern = pattern @options = options end # Allow automatic delegation of methods to the Regexp object # returned by +compile+. # # @param [ String] method The name of a method. # # @since 3.1.0 def respond_to?(method, include_private = false) if defined?(@pattern) compile.respond_to?(method, include_private) || super else # YAML calls #respond_to? during deserialization, before the object # is initialized. super end end # Encode the Raw Regexp object to BSON. # # @example Get the raw regular expression as encoded BSON. # raw_regexp.to_bson # # @note From the BSON spec: The first cstring is the regex pattern, # the second is the regex options string. Options are identified # by characters, which must be stored in alphabetical order. # Valid options are 'i' for case insensitive matching, # 'm' for multiline matching, 'x' for verbose mode, # 'l' to make \w, \W, etc. locale dependent, # 's' for dotall mode ('.' matches everything), # and 'u' to make \w, \W, etc. match unicode. # # @param [ BSON::ByteBuffer ] buffer The byte buffer to append to. # @param [ true, false ] validating_keys # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 4.2.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) return compile.to_bson(buffer, validating_keys) if options.is_a?(Integer) buffer.put_cstring(source) buffer.put_cstring(options.chars.sort.join) end # Get the raw BSON regexp as JSON hash data. # # @example Get the raw regexp as a JSON hash. # raw_regexp.as_json # # @return [ Hash ] The raw regexp as a JSON hash. # # @since 4.2.0 def as_json(*args) as_extended_json(mode: :legacy) end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash ] The extended json representation. def as_extended_json(**opts) if opts[:mode] == :legacy { "$regex" => source, "$options" => options } else {"$regularExpression" => {'pattern' => source, "options" => options}} end end # Check equality of the raw bson regexp against another. # # @example Check if the raw bson regexp is equal to the other. # raw_regexp == other # # @param [ Object ] other The object to check against. # # @return [ true, false ] If the objects are equal. # # @since 4.2.0 def ==(other) return false unless other.is_a?(::Regexp::Raw) pattern == other.pattern && options == other.options end alias :eql? :== private def method_missing(method, *arguments) return super unless respond_to?(method) compile.send(method, *arguments) end def options_to_int return options if options.is_a?(Integer) opts = 0 opts |= ::Regexp::IGNORECASE if options.include?(IGNORECASE_VALUE) opts |= ::Regexp::MULTILINE if options.include?(NEWLINE_VALUE) opts |= ::Regexp::EXTENDED if options.include?(EXTENDED_VALUE) opts end end module ClassMethods # Deserialize the regular expression from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option opts [ nil | :bson ] :mode Decoding mode to use. # # @return [ Regexp ] The decoded regular expression. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def from_bson(buffer, **opts) pattern = buffer.get_cstring options = buffer.get_cstring Raw.new(pattern, options) end end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, ::Regexp) end # Enrich the core Regexp class with this module. # # @since 2.0.0 ::Regexp.send(:include, Regexp) ::Regexp.send(:extend, Regexp::ClassMethods) end bson-ruby-4.15.0/lib/bson/registry.rb000066400000000000000000000047041423026727100174360ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Provides constant values for each to the BSON types and mappings from raw # bytes back to these types. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 module Registry extend self # A Mapping of all the BSON types to their corresponding Ruby classes. # # @since 2.0.0 MAPPINGS = {} # Get the class for the single byte identifier for the type in the BSON # specification. # # @example Get the type for the byte. # BSON::Registry.get("\x01") # # @return [ Class ] The corresponding Ruby class for the type. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def get(byte, field = nil) if type = MAPPINGS[byte] || (byte.is_a?(String) && type = MAPPINGS[byte.ord]) type else handle_unsupported_type!(byte, field) end end # Register the Ruby type for the corresponding single byte. # # @example Register the type. # BSON::Registry.register("\x01", Float) # # @param [ String ] byte The single byte. # @param [ Class ] type The class the byte maps to. # # @return [ Class ] The class. # # @since 2.0.0 def register(byte, type) MAPPINGS[byte.ord] = type define_type_reader(type) end # Raised when trying to get a type from the registry that doesn't exist. # # @since 4.1.0 class UnsupportedType < RuntimeError; end private def define_type_reader(type) type.module_eval <<-MOD def bson_type; BSON_TYPE; end MOD end def handle_unsupported_type!(byte, field) message = "Detected unknown BSON type #{byte.inspect} " message += (field ? "for fieldname \"#{field}\". " : "in array. ") message +="Are you using the latest BSON version?" raise UnsupportedType.new(message) end end end bson-ruby-4.15.0/lib/bson/specialized.rb000066400000000000000000000040661423026727100200630ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Provides behaviour to special values that exist in the BSON spec that don't # have a native type, like $minKey and $maxKey. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 module Specialized # Determine if the min key is equal to another object. # # @example Check min key equality. # BSON::MinKey.new == object # # @param [ Object ] other The object to check against. # # @return [ true, false ] If the objects are equal. # # @since 2.0.0 def ==(other) self.class == other.class end # Encode the min key - has no value since it only needs the type and field # name when being encoded. # # @example Encode the min key value. # min_key.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer end private def self.included(klass) klass.extend(ClassMethods) end module ClassMethods # Deserialize from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ Specialized ] The decoded specialized class. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def from_bson(buffer, **options) new end end end end bson-ruby-4.15.0/lib/bson/string.rb000066400000000000000000000100601423026727100170640ustar00rootroot00000000000000# -*- coding: utf-8 -*- # frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding and decoding string values to and from # raw bytes as specified by the BSON spec. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 module String # A string is type 0x02 in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(2.chr, encoding: BINARY).freeze # Regex for matching illegal BSON keys. # # @since 4.1.0 ILLEGAL_KEY = /(\A[$])|(\.)/ # Get the string as encoded BSON. # # @example Get the string as encoded BSON. # "test".to_bson # # @raise [ EncodingError ] If the string is not UTF-8. # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_string(self) end # Get the string as a BSON key name encoded C string with checking for special characters. # # @example Get the string as key name. # "test".to_bson_key # # @raise [ EncodingError ] If the string is not UTF-8. # # @raise [ IllegalKey ] If validating keys and it contains a '.' or starts # with '$'. # # @return [ String ] The encoded string. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson_key(validating_keys = Config.validating_keys?) if validating_keys raise IllegalKey.new(self) if ILLEGAL_KEY =~ self end self end # Convert the string to an object id. This will only work for strings of size # 12. # # @example Convert the string to an object id. # string.to_bson_object_id # # @note This is used for repairing legacy bson data. # # @raise [ BSON::ObjectId::Invalid ] If the string is not 12 elements. # # @return [ String ] The raw object id bytes. # # @since 2.0.0 def to_bson_object_id ObjectId.repair(self) end # Convert the string to a hexidecimal representation. # # @example Convert the string to hex. # "\x01".to_hex_string # # @return [ String ] The string as hex. # # @since 2.0.0 def to_hex_string unpack("H*")[0] end # Raised when validating keys and a key is illegal in MongoDB # # @since 4.1.0 class IllegalKey < RuntimeError # Instantiate the exception. # # @example Instantiate the exception. # BSON::Object::IllegalKey.new(string) # # @param [ String ] string The illegal string. # # @since 4.1.0 def initialize(string) super("'#{string}' is an illegal key in MongoDB. Keys may not start with '$' or contain a '.'.") end end module ClassMethods # Deserialize a string from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ Regexp ] The decoded string. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def from_bson(buffer, **options) buffer.get_string end end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, ::String) end # Enrich the core String class with this module. # # @since 2.0.0 ::String.send(:include, String) ::String.send(:extend, String::ClassMethods) end bson-ruby-4.15.0/lib/bson/symbol.rb000066400000000000000000000140621423026727100170710ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding and decoding symbol values to and from # raw bytes as specified by the BSON spec. # # @note Symbols are deprecated in the BSON spec, but they are still # currently supported here for backwards compatibility. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 module Symbol # A symbol is type 0x0E in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(14.chr, encoding: BINARY).freeze # Symbols are serialized as strings as symbols are now removed from the # BSON specification. Therefore the bson_type when serializing must be a # string. # # @example Get the BSON type for the symbol. # :test.bson_type # # @return [ String ] The single byte BSON type. # # @see http://bsonspec.org/#/specification # # @since 4.0.0 def bson_type String::BSON_TYPE end # Get the symbol as encoded BSON. # # @example Get the symbol as encoded BSON. # :test.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_symbol(self) end # Get the symbol as a BSON key name encoded C symbol. # # @example Get the symbol as a key name. # :test.to_bson_key # # @return [ String ] The encoded symbol as a BSON key. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson_key(validating_keys = Config.validating_keys?) if validating_keys raise BSON::String::IllegalKey.new(self) if BSON::String::ILLEGAL_KEY =~ self end self end # Converts the symbol to a normalized key in a BSON document. # # @example Convert the symbol to a normalized key. # :test.to_bson_normalized_key # # @return [ String ] The symbol as a non interned string. # # @since 3.0.0 def to_bson_normalized_key to_s end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # @option options [ true | false ] :relaxed Whether to produce relaxed # extended JSON representation. # # @return [ Hash ] The extended json representation. def as_extended_json(**options) { "$symbol" => to_s } end class Raw # Create a BSON Symbol # # @param [ String | Symbol ] str_or_sym The symbol represented by this # object. Can be specified as a Symbol or a String. # # @see http://bsonspec.org/#/specification def initialize(str_or_sym) unless str_or_sym.is_a?(String) || str_or_sym.is_a?(Symbol) raise ArgumentError, "BSON::Symbol::Raw must be given a symbol or a string, not #{str_or_sym}" end @symbol = str_or_sym.to_sym end # Get the underlying symbol as a Ruby symbol. # # @return [ Symbol ] The symbol represented by this BSON object. def to_sym @symbol end # Get the underlying symbol as a Ruby string. # # @return [ String ] The symbol as a string. def to_s @symbol.to_s end # Check equality of the raw bson symbol against another. # # @param [ Object ] other The object to check against. # # @return [ true, false ] If the objects are equal. def ==(other) return false unless other.is_a?(Raw) to_sym == other.to_sym end alias :eql? :== # Get the symbol as encoded BSON. # # @raise [ EncodingError ] If the symbol is not UTF-8. # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_string(to_s) end def bson_type Symbol::BSON_TYPE end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # This method returns the integer value if relaxed representation is # requested, otherwise a $numberLong hash. # # @option options [ true | false ] :relaxed Whether to produce relaxed # extended JSON representation. # # @return [ Hash | Integer ] The extended json representation. def as_extended_json(**options) {'$symbol' => to_s} end end module ClassMethods # Deserialize a symbol from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ Symbol | BSON::Symbol::Raw ] The decoded symbol. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def from_bson(buffer, **options) sym = buffer.get_string.intern if options[:mode] == :bson Raw.new(sym) else sym end end end # Register this type when the module is loaded. # # @since 2.0.0 Registry::MAPPINGS[BSON_TYPE.ord] = ::Symbol end # Enrich the core Symbol class with this module. # # @since 2.0.0 ::Symbol.send(:include, Symbol) ::Symbol.send(:extend, Symbol::ClassMethods) end bson-ruby-4.15.0/lib/bson/time.rb000066400000000000000000000106411423026727100165210ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding and decoding time values to # and from raw bytes as specified by the BSON spec. # # @note # Ruby time can have nanosecond precision: # +Time.utc(2020, 1, 1, 0, 0, 0, 999_999_999/1000r)+ # +Time#usec+ returns the number of microseconds in the time, and # if the time has nanosecond precision the sub-microsecond part is # truncated (the value is floored to the nearest millisecond). # MongoDB only supports millisecond precision; we truncate the # sub-millisecond part of microseconds (floor to the nearest millisecond). # Note that if a time is constructed from a floating point value, # the microsecond value may round to the starting floating point value # but due to flooring, the time after serialization may end up to # be different than the starting floating point value. # It is recommended that time calculations use integer math only. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 module Time # A time is type 0x09 in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(9.chr, encoding: BINARY).freeze # Get the time as encoded BSON. # # @note The time is floored to the nearest millisecond. # # @example Get the time as encoded BSON. # Time.new(2012, 1, 1, 0, 0, 0).to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) value = _bson_to_i * 1000 + usec.divmod(1000).first buffer.put_int64(value) end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # @note The time is floored to the nearest millisecond. # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash ] The extended json representation. def as_extended_json(**options) utc_time = utc if options[:mode] == :relaxed && (1970..9999).include?(utc_time.year) if utc_time.usec != 0 if utc_time.respond_to?(:floor) # Ruby 2.7+ utc_time = utc_time.floor(3) else utc_time -= utc_time.usec.divmod(1000).last.to_r / 1000000 end {'$date' => utc_time.strftime('%Y-%m-%dT%H:%M:%S.%LZ')} else {'$date' => utc_time.strftime('%Y-%m-%dT%H:%M:%SZ')} end else sec = utc_time._bson_to_i msec = utc_time.usec.divmod(1000).first {'$date' => {'$numberLong' => (sec * 1000 + msec).to_s}} end end def _bson_to_i # Workaround for JRuby's #to_i rounding negative timestamps up # rather than down (https://github.com/jruby/jruby/issues/6104) if BSON::Environment.jruby? (self - usec.to_r/1000000).to_i else to_i end end module ClassMethods # Deserialize UTC datetime from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ Time ] The decoded UTC datetime. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def from_bson(buffer, **options) seconds, fragment = Int64.from_bson(buffer, mode: nil).divmod(1000) at(seconds, fragment * 1000).utc end end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, ::Time) end # Enrich the core Time class with this module. # # @since 2.0.0 ::Time.send(:include, Time) ::Time.send(:extend, Time::ClassMethods) end bson-ruby-4.15.0/lib/bson/time_with_zone.rb000066400000000000000000000034051423026727100206070ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2018-2020 MongoDB Inc. # # 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. require "active_support/time_with_zone" module BSON # Injects behaviour for encoding ActiveSupport::TimeWithZone values to # raw bytes as specified by the BSON spec for time. # # @see http://bsonspec.org/#/specification # # @since 4.4.0 module TimeWithZone # Get the ActiveSupport::TimeWithZone as encoded BSON. # # @example Get the ActiveSupport::TimeWithZone as encoded BSON. # Time.utc(2012, 12, 12, 0, 0, 0).in_time_zone("Pacific Time (US & Canada)").to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 4.4.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_int64((to_i * 1000) + (usec / 1000)) end # Get the BSON type for the ActiveSupport::TimeWithZone. # # As the ActiveSupport::TimeWithZone is converted to a time, this returns # the BSON type for time. def bson_type ::Time::BSON_TYPE end end # Enrich the ActiveSupport::TimeWithZone class with this module. # # @since 4.4.0 ActiveSupport::TimeWithZone.send(:include, TimeWithZone) end bson-ruby-4.15.0/lib/bson/timestamp.rb000066400000000000000000000107401423026727100175660ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Represents a timestamp type, which is predominately used for sharding. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 class Timestamp include JSON include Comparable # A timestamp is type 0x11 in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(17.chr, encoding: BINARY).freeze # Error message if an object other than a Timestamp is compared with this object. # # @since 4.3.0 COMPARISON_ERROR_MESSAGE = 'comparison of %s with Timestamp failed' # @!attribute seconds # @return [ Integer ] The number of seconds. # @since 2.0.0 # # @!attribute increment # @return [ Integer ] The incrementing value. # @since 2.0.0 # attr_reader :seconds, :increment # Determine if this timestamp is equal to another object. # # @example Check the timestamp equality. # timestamp == other # # @param [ Object ] other The object to compare against. # # @return [ true, false ] If the objects are equal. # # @since 2.0.0 def ==(other) return false unless other.is_a?(Timestamp) seconds == other.seconds && increment == other.increment end # Determine if this timestamp is greater or less than another object. # # @example Compare the timestamp. # timestamp < other # # @param [ Object ] other The object to compare against. # # @return [ true, false ] The result of the comparison. # # @since 4.3.0 def <=>(other) raise ArgumentError.new(COMPARISON_ERROR_MESSAGE % other.class) unless other.is_a?(Timestamp) return 0 if self == other a = [ seconds, increment ] b = [ other.seconds, other.increment ] [ a, b ].sort[0] == a ? -1 : 1 end # Get the timestamp as JSON hash data. # # @example Get the timestamp as a JSON hash. # timestamp.as_json # # @return [ Hash ] The timestamp as a JSON hash. # # @since 2.0.0 # @deprecated Use as_extended_json instead. def as_json(*args) as_extended_json end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash ] The extended json representation. def as_extended_json(**options) { "$timestamp" => { "t" => seconds, "i" => increment } } end # Instantiate the new timestamp. # # @example Instantiate the timestamp. # BSON::Timestamp.new(5, 30) # # @param [ Integer ] seconds The number of seconds. # @param [ Integer ] increment The increment value. # # @since 2.0.0 def initialize(seconds, increment) @seconds, @increment = seconds, increment end # Get the timestamp as its encoded raw BSON bytes. # # @example Get the timestamp as BSON. # timestamp.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_uint32(increment) buffer.put_uint32(seconds) end # Deserialize timestamp from BSON. # # @param [ ByteBuffer ] buffer The byte buffer. # # @option options [ nil | :bson ] :mode Decoding mode to use. # # @return [ Timestamp ] The decoded timestamp. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def self.from_bson(buffer, **options) increment = buffer.get_uint32 seconds = buffer.get_uint32 new(seconds, increment) end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, self) end end bson-ruby-4.15.0/lib/bson/true_class.rb000066400000000000000000000033411423026727100177260ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Injects behaviour for encoding and decoding true values to and from # raw bytes as specified by the BSON spec. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 module TrueClass # A true value in the BSON spec is 0x01. # # @since 2.0.0 TRUE_BYTE = ::String.new(1.chr, encoding: BINARY).freeze # The BSON type for true values is the general boolean type of 0x08. # # @example Get the bson type. # false.bson_type # # @return [ String ] The character 0x08. # # @since 2.0.0 def bson_type Boolean::BSON_TYPE end # Get the true boolean as encoded BSON. # # @example Get the true boolean as encoded BSON. # true.to_bson # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?) buffer.put_byte(TRUE_BYTE) end end # Enrich the core TrueClass class with this module. # # @since 2.0.0 ::TrueClass.send(:include, TrueClass) end bson-ruby-4.15.0/lib/bson/undefined.rb000066400000000000000000000034451423026727100175300ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON # Represents the Undefined BSON type # # @see http://bsonspec.org/#/specification # # @since 2.0.0 class Undefined include Specialized # Undefined is type 0x06 in the BSON spec. # # @since 2.0.0 BSON_TYPE = ::String.new(6.chr, encoding: BINARY).freeze # Determine if undefined is equal to another object. # # @example Check undefined equality. # BSON::Undefined.new == object # # @param [ Object ] other The object to check against. # # @return [ true, false ] If the objects are equal. # # @since 2.0.0 def ==(other) self.class == other.class end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst). # # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode # (default is canonical extended JSON) # # @return [ Hash ] The extended json representation. def as_extended_json(**options) { "$undefined" => true } end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, self) end end bson-ruby-4.15.0/lib/bson/version.rb000066400000000000000000000012131423026727100172430ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2009-2020 MongoDB Inc. # # 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. module BSON VERSION = "4.15.0" end bson-ruby-4.15.0/perf/000077500000000000000000000000001423026727100144615ustar00rootroot00000000000000bson-ruby-4.15.0/perf/README.md000066400000000000000000000030131423026727100157350ustar00rootroot00000000000000Performance Notes ================= Pending ------- - codepoints and getbyte, setbyte, << for BSON_TYPE - string.force_encoding("UTF-8").valid_encoding? Top concerns ------------ - String - pure - cext@ - Tyler has experience, says UTF8 (with LATIN1 subset) is sufficient, note keys need special char check - to_utf8_binary@ - to_bson_string@ - to_bson_cstring@ - append_bson_int32 - to_bson_key - rb_string_to_bson_key - check_for_illegal_characters - encode - set_int32 - force_encoding - to_bson - Symbol - to_bson - to_bson_key - rb_symbol_to_bson_key - Binary - rb_binary_to_bson - Integer - sizing done twice for serialization - bson_type and to_bson - discarded as not worthy - new_hash_to_bson_hint - new_hash_to_bson_integer - Array to_bson - repeat above TODO: Review ------------ - key optimization - note threading concerns - no safety limit needed for non-pathological use (review this) - symbol ~ gain: 0.25 (36 --> 27) Xeon, gain: 0.34 (41 --> 27) Core 2 - string ~ gain: 0.15 (33 --> 28) Xeon, gain: 0.24 (39 --> 29) Core 2 - with safety limit, mutex overhead eats up the benefit on Xeon - symbol ~ gain: 0.15 (41 --> 35) Core 2 - string ~ gain: 0.05 (39 --> 37) Core 2 - rb_float_to_bson ~ gain: 0.61 (15 --> 6, allocated: 3 --> 1) Core 2 Performance gains ----------------- - catalog, extract techniques, tech talk Driver notes ------------ Check for initial '$' or inclusion of '.' is purposely left to the driver. See bench.rb: test_string_to_bson_key_mongodb bson-ruby-4.15.0/perf/Rakefile000066400000000000000000000040541423026727100161310ustar00rootroot00000000000000# Copyright (C) 2009-2013 MongoDB Inc. # # 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. require 'json' # test framework for C extension versus pure Ruby # (consider ENV for C versus C) DEFAULT_TARGET = 'test_ext_rb_float_to_bson' NON_ZERO_TIME = 0.0000000001 # 10^-10 def sh_eval(command) puts command text = `#{command}` lines = text.split("\n") ruby_on = lines.grep(/^[^.#\w]/).first if lines.grep(/Error/).first print text raise "sh_eval error" elsif ruby_on eval lines.grep(/^[^.#\w]/).first else raise "no Ruby data - check the TARGET" end end def hash_f(hash, precision) hash.each_pair do |key, value| hash[key] = "%.#{precision}f" % value if value.kind_of?(Float) end end def print_gain(measurement) measurement = measurement.collect do |h| h[:allocated] = h[:allocated] / h[:count] h[:label] = "\"#{h[:label]}\"" h.select{|k,v| [:label, :utime, :real, :allocated].include?(k)} end gain = 1.0 - measurement[1][:utime]/(measurement[0][:utime] + NON_ZERO_TIME) measurement.each do |t| puts hash_f(t, 1).each_pair.collect{|key, value| "#{key}: #{value}" }.join(', ') end puts "gain: #{'%.2f' % gain}" end $measurement = [] task :default do TARGET = ENV['TARGET'] || DEFAULT_TARGET $measurement = [] [:clean, :compile].each do |t| Rake::Task[t].execute Rake::Task[:test].execute end print_gain($measurement) end task :clean do sh "(cd .. && rake clean)" end task :compile do sh "(cd .. && rake compile)" end task :test do $measurement << sh_eval("ruby bench_test.rb --name #{TARGET}") end bson-ruby-4.15.0/perf/bench.rb000066400000000000000000000153211423026727100160670ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. $:.unshift File.join(File.dirname(__FILE__), "..", "lib") require "benchmark" def benchmark! count = 1_000_000 Benchmark.bm do |bench| document = BSON::Document.new(field1: 'testing', field2: 'testing') embedded = 5.times.map do |i| BSON::Document.new(field1: 10, field2: 'test') end document[:embedded] = embedded bench.report("Document#to_bson ------>") do count.times { document.to_bson } end bench.report("Binary#to_bson -------->") do count.times { BSON::Binary.new("test", :generic).to_bson } end bench.report("Code#to_bson ---------->") do count.times { BSON::Code.new("this.value = 1").to_bson } end big_decimal = BigDecimal(123) bench.report("Decimal128#to_bson ---->") do count.times { BSON::Decimal128.new(big_decimal).to_bson } end bench.report("FalseClass#to_bson ---->") do count.times { false.to_bson } end bench.report("Float#to_bson --------->") do count.times { 1.131312.to_bson } end bench.report("Integer#to_bson ------->") do count.times { 1024.to_bson } end bench.report("MaxKey#to_bson -------->") do count.times { BSON::MaxKey.new.to_bson } end bench.report("MinKey#to_bson -------->") do count.times { BSON::MinKey.new.to_bson } end bench.report("ObjectId#to_bson ------>") do count.times { BSON::ObjectId.new.to_bson } end bench.report("ObjectId#to_s --------->") do object_id = BSON::ObjectId.new count.times { object_id.to_s } end bench.report("Regexp#to_bson -------->") do count.times { %r{\d+}.to_bson } end bench.report("String#to_bson -------->") do count.times { "testing".to_bson } end bench.report("Symbol#to_bson -------->") do count.times { "testing".to_bson } end bench.report("Time#to_bson ---------->") do count.times { Time.new.to_bson } end bench.report("TrueClass#to_bson ----->") do count.times { true.to_bson } end boolean_bytes = true.to_bson.to_s bench.report("Boolean#from_bson ----->") do count.times { BSON::Boolean.from_bson(BSON::ByteBuffer.new(boolean_bytes)) } end int32_bytes = 1024.to_bson.to_s bench.report("Int32#from_bson ------->") do count.times { BSON::Int32.from_bson(BSON::ByteBuffer.new(int32_bytes)) } end int64_bytes = (BSON::Integer::MAX_32BIT + 1).to_bson.to_s bench.report("Int64#from_bson ------->") do count.times { BSON::Int64.from_bson(BSON::ByteBuffer.new(int64_bytes)) } end float_bytes = 1.23131.to_bson.to_s bench.report("Float#from_bson ------->") do count.times { Float.from_bson(BSON::ByteBuffer.new(float_bytes)) } end binary_bytes = BSON::Binary.new("test", :generic).to_bson.to_s bench.report("Binary#from_bson ------>") do count.times { BSON::Binary.from_bson(BSON::ByteBuffer.new(binary_bytes)) } end code_bytes = BSON::Code.new("this.value = 1").to_bson.to_s bench.report("Code#from_bson -------->") do count.times { BSON::Code.from_bson(BSON::ByteBuffer.new(code_bytes)) } end decimal128_bytes = BSON::Decimal128.new(BigDecimal(123)).to_bson.to_s bench.report("Decimal128#from_bson -->") do count.times { BSON::Decimal128.from_bson(BSON::ByteBuffer.new(decimal128_bytes)) } end false_bytes = false.to_bson.to_s bench.report("Boolean#from_bson ----->") do count.times { BSON::Boolean.from_bson(BSON::ByteBuffer.new(false_bytes)) } end max_key_bytes = BSON::MaxKey.new.to_bson.to_s bench.report("MaxKey#from_bson ------>") do count.times { BSON::MaxKey.from_bson(BSON::ByteBuffer.new(max_key_bytes)) } end min_key_bytes = BSON::MinKey.new.to_bson.to_s bench.report("MinKey#from_bson ------>") do count.times { BSON::MinKey.from_bson(BSON::ByteBuffer.new(min_key_bytes)) } end object_id_bytes = BSON::ObjectId.new.to_bson.to_s bench.report("ObjectId#from_bson ---->") do count.times { BSON::ObjectId.from_bson(BSON::ByteBuffer.new(object_id_bytes)) } end regex_bytes = %r{\d+}.to_bson.to_s bench.report("Regexp#from_bson ------>") do count.times { Regexp.from_bson(BSON::ByteBuffer.new(regex_bytes)) } end string_bytes = "testing".to_bson.to_s bench.report("String#from_bson ------>") do count.times { String.from_bson(BSON::ByteBuffer.new(string_bytes)) } end symbol_bytes = "testing".to_bson.to_s bench.report("Symbol#from_bson ------>") do count.times { Symbol.from_bson(BSON::ByteBuffer.new(symbol_bytes)) } end time_bytes = Time.new.to_bson.to_s bench.report("Time#from_bson -------->") do count.times { Time.from_bson(BSON::ByteBuffer.new(time_bytes)) } end doc_bytes = document.to_bson.to_s bench.report("Document#from_bson ---->") do count.times { BSON::Document.from_bson(BSON::ByteBuffer.new(doc_bytes)) } end end end def benchmark_decimal128_from_string! test_helpers = Dir.glob(File.join(Dir.pwd, 'spec/support/common_driver.rb')) test_helpers.each { |t| require t } count = 100_000 test_files = Dir.glob(File.join(Dir.pwd, 'spec/support/driver-spec-tests/**/*.json')) tests = test_files.map { |file| BSON::CommonDriver::Spec.new(file) } tests[4].valid_tests.each do |test| puts test.string Benchmark.bm do |bench| bench.report("Decimal128#new from String ------>") do count.times { BSON::Decimal128.from_string(test.string) } end end end end def benchmark_decimal128_to_string! test_helpers = Dir.glob(File.join(Dir.pwd, 'spec/support/common_driver.rb')) test_helpers.each { |t| require t } count = 100_000 test_files = Dir.glob(File.join(Dir.pwd, 'spec/support/driver-spec-tests/**/*.json')) test_groups = test_files.map { |file| BSON::CommonDriver::Spec.new(file) } test_groups.each do |tests| tests.valid_tests.each do |test| decimal128 = BSON::Decimal128.from_string(test.string) puts decimal128.to_s Benchmark.bm do |bench| bench.report("Decimal128#to_string ------>") do count.times { BSON::Decimal128::Builder::ToString.new(decimal128).string } end end end end end bson-ruby-4.15.0/perf/bench_test.rb000066400000000000000000000727001423026727100171320ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) require 'bson' require 'json' require 'stringio' require 'test/unit' require 'benchmark' require 'ruby-prof' unless RUBY_PLATFORM =~ /java/ class BenchTest < Test::Unit::TestCase RESET = 'reset' NON_ZERO_TIME = 0.0000000001 # 10^-10 def setup puts @label_width = 30 end def teardown puts end def gc_allocated gc_stat = [] GC.start gc_stat << GC.stat result = yield GC.start gc_stat << GC.stat [ result, gc_stat[1][:total_allocated_object] - gc_stat[0][:total_allocated_object] ] end def print_measurement_and_gain(measurement, j) h = measurement[j] h[:allocated] /= h[:count] if j > 0 h[:base] = measurement[0][:utime] h[:gain] = 1.0 - h[:utime] / (h[:base] + NON_ZERO_TIME) end [ [ "label: \"%s\"", :label ], [ ", allocated: %d", :allocated ], [ ", user: %.1f", :utime ], [ ", base: %.1f", :base ], [ ", gain: %.2f", :gain ] ].each do |format, key| print (format % h[key]) if h[key] end puts end def benchmark_methods_with_gc(count, method_label_pairs) measurement = [] method_label_pairs.each_with_index do |method_label_pair, j| meth, label = method_label_pair meth.call htms, allocated = gc_allocated do tms = Benchmark.measure(label) do count.times.each_with_index {|i| yield i } end Hash[*[:label, :utime, :stime, :cutime, :cstime, :real].zip(tms.to_a).flatten] end htms.merge!({allocated: allocated, count: count}) measurement << htms print_measurement_and_gain(measurement, j) end reset_method = method_label_pairs.find(method_label_pairs.first){|ml| ml[2] && ml[2] == RESET}.first reset_method.call end # Optimization committed -------------------------------------------------------------------------------------------- def old_array_index BSON.module_eval <<-EVAL module Array def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) encode_with_placeholder_and_null(BSON_ADJUST, encoded) do |encoded| each_with_index do |value, index| encoded << value.bson_type index.to_s.to_bson_key(encoded) value.to_bson(encoded) end end end end EVAL end def new_array_index_optimize BSON.module_eval <<-EVAL module Array @@_BSON_INDEX_SIZE = 1024 @@_BSON_INDEX_ARRAY = ::Array.new(@@_BSON_INDEX_SIZE){|i| (i.to_s.force_encoding(BINARY) << NULL_BYTE).freeze}.freeze def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) encode_with_placeholder_and_null(BSON_ADJUST, encoded) do |encoded| each_with_index do |value, index| encoded << value.bson_type if index < @@_BSON_INDEX_SIZE encoded << @@_BSON_INDEX_ARRAY[index] else index.to_s.to_bson_cstring(encoded) end value.to_bson(encoded) end end end end EVAL end def test_array_index_optimization size = 1024 array = Array.new(size){|i| i} method_label_pairs = [ [ method(:old_array_index), 'Array index optimize none' ], [ method(:new_array_index_optimize), 'Array index optimize 1024', RESET ] # Xeon user: 20.3, base: 33.2, gain: 0.39 ] benchmark_methods_with_gc(1_000, method_label_pairs) { array.to_bson } end def old_encode_bson_with_placeholder BSON.module_eval <<-EVAL module Encodable def encode_with_placeholder_and_null(adjust, encoded = ''.force_encoding(BINARY)) pos = encoded.bytesize encoded << PLACEHOLDER yield(encoded) encoded << NULL_BYTE encoded[pos, 4] = (encoded.bytesize - pos + adjust).to_bson encoded end end EVAL end def new_encode_bson_with_placeholder_to_bson_int32 BSON.module_eval <<-EVAL module Encodable def encode_with_placeholder_and_null(adjust, encoded = ''.force_encoding(BINARY)) pos = encoded.bytesize encoded << PLACEHOLDER yield(encoded) encoded << NULL_BYTE encoded[pos, 4] = (encoded.bytesize - pos + adjust).to_bson_int32('') encoded end end EVAL end def new_encode_bson_with_placeholder_set_int32 BSON.module_eval <<-EVAL module Encodable def encode_with_placeholder_and_null(adjust, encoded = ''.force_encoding(BINARY)) pos = encoded.bytesize encoded << PLACEHOLDER yield(encoded) encoded << NULL_BYTE encoded.set_int32(pos, encoded.bytesize - pos + adjust) encoded end end EVAL end def test_encode_bson_with_placeholder size = 1 hash = Hash[*(0..size).to_a.collect{|i| [ ('a' + i.to_s), i.to_s]}.flatten] method_label_pairs = [ [ method(:old_encode_bson_with_placeholder), 'Encode bson optimize to_bson' ], [ method(:new_encode_bson_with_placeholder_to_bson_int32), 'Encode bson optimize to_bson_int32' ], # user: 22.2, base: 28.5, gain: 0.22 [ method(:new_encode_bson_with_placeholder_set_int32), 'Encode bson optimize set_int32', RESET ] # user: 22.2, base: 28.5, gain: 0.22 ] benchmark_methods_with_gc(1_000_000, method_label_pairs) { hash.to_bson } end def old_integer_to_bson BSON.module_eval <<-EVAL module Integer def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) unless bson_int64? out_of_range! else bson_int32? ? to_bson_int32(encoded) : to_bson_int64(encoded) end end end EVAL end def new_integer_to_bson BSON.module_eval <<-EVAL module Integer def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) if bson_int32? to_bson_int32(encoded) elsif bson_int64? to_bson_int64(encoded) else out_of_range! end end end EVAL end def test_integer_to_bson_optimization size = 1024 hash = Hash[*(0..size).to_a.collect{|i| [ ('a' + i.to_s).to_sym, i]}.flatten] method_label_pairs = [ [ method(:old_integer_to_bson), 'Integer to_bson optimize none' ], [ method(:new_integer_to_bson), 'Integer to_bson optimize test order', RESET ] ] benchmark_methods_with_gc(2_000, method_label_pairs) { hash.to_bson } end def old_nilclass_to_bson BSON.module_eval <<-EVAL module NilClass def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) encoded << NO_VALUE end end EVAL end def new_nilclass_to_bson BSON.module_eval <<-EVAL module NilClass def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) encoded end end EVAL end def test_nilclass_to_bson_optimization method_label_pairs = [ [ method(:old_nilclass_to_bson), 'Nil to_bson optimize none' ], [ method(:new_nilclass_to_bson), 'Nil to_bson optimize noop', RESET ] # Core2 user: 4.9, base: 5.7, gain: 0.14 ] benchmark_methods_with_gc(20_000_000, method_label_pairs) { nil.to_bson } end # C extension ------------------------------------------------------------------------------------------------------- def benchmark_for_ext(count, label) htms, allocated = gc_allocated do tms = Benchmark.measure(label) do count.times.each_with_index {|i| yield i } end Hash[*[:label, :utime, :stime, :cutime, :cstime, :real].zip(tms.to_a).flatten] end htms.merge!({allocated: allocated, count: count}) end #label: "test_ext_rb_string_check_for_illegal_characters!", utime: 19.3, real: 19.7, allocated: 3 #label: "test_ext_rb_string_check_for_illegal_characters!", utime: 16.3, real: 16.6, allocated: 4 #gain: 0.15 def test_ext_rb_string_check_for_illegal_characters! p (benchmark_for_ext(10_000_000, __method__) { "Hello World!".to_bson_cstring }) end #label: test_ext_rb_float_to_bson, utime: 15.4, real: 16.1, allocated: 3 #label: test_ext_rb_float_to_bson, utime: 6.1, real: 6.3, allocated: 1 #gain: 0.61 def test_ext_rb_float_to_bson p (benchmark_for_ext(10_000_000, __method__) { 3.14159.to_bson }) end #label: "test_ext_rb_time_to_bson", utime: 26.5, real: 26.6, allocated: 6 #label: "test_ext_rb_time_to_bson", utime: 13.3, real: 13.4, allocated: 4 #gain: 0.50 def test_ext_rb_time_to_bson t = Time.now p (benchmark_for_ext(10_000_000, __method__) { t.to_bson }) end #label: "test_ext_rb_integer_to_bson_key_large", utime: 18.9, real: 19.1, allocated: 1 #label: "test_ext_rb_integer_to_bson_key_large", utime: 3.7, real: 3.8, allocated: 0 #gain: 0.80 def test_ext_rb_integer_to_bson_key_large bson = String.new.force_encoding(BSON::BINARY) p (benchmark_for_ext(10_000_000, __method__) {|i| i.to_bson_key(bson); bson.clear }) end #label: "test_ext_rb_integer_to_bson_key_small", utime: 33.5, real: 34.2, allocated: 0 #label: "test_ext_rb_integer_to_bson_key_small", utime: 25.4, real: 25.8, allocated: 0 #gain: 0.24 def test_ext_rb_integer_to_bson_key_small bson = String.new.force_encoding(BSON::BINARY) p (benchmark_for_ext(10_0000_000, __method__) {|i| 1023.to_bson_key(bson); bson.clear }) end #label: "test_ext_rb_symbol_to_bson", utime: 36.5, real: 37.0, allocated: 5 #label: "test_ext_rb_symbol_to_bson", utime: 24.2, real: 24.3, allocated: 3 #gain: 0.34 # rb_symbol_to_bson - no C ext, just benefit from other C ext functions def test_ext_rb_symbol_to_bson bson = String.new.force_encoding(BSON::BINARY) p (benchmark_for_ext(10_000_000, __method__) { :my_symbol.to_bson }) end # Optimization NOT committed ---------------------------------------------------------------------------------------- # MongoDB driver overrides ------------------------------------------------------------------------------------------ def old_string_to_bson_key BSON.module_eval <<-EVAL module String def to_bson_key(encoded = ''.force_encoding(BINARY)) to_bson_cstring(encoded) end end EVAL end def new_string_to_bson_key_flag BSON.module_eval <<-EVAL module String def to_bson_key(encoded = ''.force_encoding(BINARY)) nil if encoded.instance_variable_get(:@bson_key_check_skip) to_bson_cstring(encoded) end end EVAL end def new_string_to_bson_key_mongodb BSON.module_eval <<-EVAL module String def to_bson_key(encoded = ''.force_encoding(BINARY)) check_for_illegal_mongodb_key_characters!(encoded) to_bson_cstring(encoded) end def check_for_illegal_mongodb_key_characters!(encoded) unless encoded.instance_variable_get(:@bson_key_check_skip) raise "key \#{self.inspect} must not start with '$'" if self[0] == ?$ raise "key \#{self.inspect} must not contain '.'" if self.include? ?. end end end EVAL end #label: "string to_bson_key", allocated: 2, user: 18.3 #label: "string to_bson_key flag check", allocated: 2, user: 19.6, base: 18.3, gain: -0.07 #label: "string to_bson_key mongodb", allocated: 2, user: 20.6, base: 18.3, gain: -0.12 def test_string_to_bson_key_mongodb encoded = '' encoded.instance_variable_set(:@bson_key_check_skip, true) method_label_pairs = [ [ method(:old_string_to_bson_key), 'string to_bson_key', RESET ], [ method(:new_string_to_bson_key_flag), 'string to_bson_key flag check' ], [ method(:new_string_to_bson_key_mongodb), 'string to_bson_key mongodb' ] # Core2 user: 29.5, base: 29.0, gain: -0.02 ] benchmark_methods_with_gc(10_000_000, method_label_pairs) { 'email_address'.to_bson_key(encoded); encoded.clear } end # Discarded as not worthy ------------------------------------------------------------------------------------------- # user system total real #test_encode_twitter 289.520000 0.900000 290.420000 (294.547515) to_bson no hint pure #allocated: 11563746 allocated/line: 224 #test_encode_twitter 293.320000 0.910000 294.230000 (298.737329) to_bson hint pure #allocated: 11423424 allocated/line: 222 def old_hash_to_bson_no_hint BSON.module_eval <<-EVAL module Hash def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) encode_with_placeholder_and_null(BSON_ADJUST, encoded) do |encoded| each do |field, value| encoded << value.bson_type field.to_bson_key(encoded) value.to_bson(encoded) end end end end EVAL end def new_hash_to_bson_hint BSON.module_eval <<-EVAL module Hash def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) encode_with_placeholder_and_null(BSON_ADJUST, encoded) do |encoded| each do |field, value| encoded << (bson_type = value.bson_type) field.to_bson_key(encoded) value.to_bson(encoded, bson_type) end end end end module Integer def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) if hint == Int32::BSON_TYPE to_bson_int32(encoded) elsif hint == Int64::BSON_TYPE to_bson_int64(encoded) elsif bson_int32? to_bson_int32(encoded) elsif bson_int64? to_bson_int64(encoded) else out_of_range! end end end module String def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) encode_with_placeholder_and_null(STRING_ADJUST, encoded) do |encoded| to_bson_string(encoded) end end end EVAL end def test_hash_integer_to_bson_hint size = 1024 hash = Hash[*(0..size).to_a.collect{|i| [ ('a' + i.to_s), i]}.flatten] method_label_pairs = [ [ method(:old_hash_to_bson_no_hint), 'Hash integer to_bson no hint' ], [ method(:new_hash_to_bson_hint), 'Hash integer to_bson hint', RESET ], # Core2 user: 25.1, base: 33.8, gain: 0.26 ] benchmark_methods_with_gc(4_000, method_label_pairs) { hash.to_bson } end def test_hash_string_to_bson_hint # to check overhead of hint setting and passing size = 1024 hash = Hash[*(0..size).to_a.collect{|i| [ ('a' + i.to_s), i.to_s]}.flatten] method_label_pairs = [ [ method(:old_hash_to_bson_no_hint), 'Hash string to_bson no hint', RESET ], [ method(:new_hash_to_bson_hint), 'Hash string to_bson hint' ], # Core2 user: 19.8, base: 19.7, gain: -0.00 ] benchmark_methods_with_gc(4_000, method_label_pairs) { hash.to_bson } end def old_hash_to_bson BSON.module_eval <<-EVAL module Hash def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) encode_with_placeholder_and_null(BSON_ADJUST, encoded) do |encoded| each do |field, value| encoded << value.bson_type field.to_bson_key(encoded) value.to_bson(encoded) end end end end EVAL end def new_hash_to_bson_v0 # if-else seems to work better than setting a variable to method # pending - mutex BSON.module_eval <<-EVAL module Hash @@_memo_threshold = 65535 @@_memo_hash = ::Hash.new @@_memo_mutex = Mutex.new def _memo_set(field) @@_memo_mutex.synchronize do @@_memo_hash[field] = @@_memo_hash.fetch(field) { yield } end end def _memo_fetch(field) @@_memo_mutex.synchronize do @@_memo_hash.fetch(field) { yield } end end def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) if size < @@_memo_threshold encode_with_placeholder_and_null(BSON_ADJUST, encoded) do |encoded| each do |field, value| encoded << value.bson_type encoded << _memo_set(field) { field.to_bson_key } value.to_bson(encoded) end end else encode_with_placeholder_and_null(BSON_ADJUST, encoded) do |encoded| each do |field, value| encoded << value.bson_type encoded << _memo_fetch(field) { field.to_bson_key } value.to_bson(encoded) end end end end end EVAL end def new_hash_to_bson_v1 BSON.module_eval <<-EVAL module Hash @@_memo_hash = ::Hash.new def _memo(field) @@_memo_hash[field] = @@_memo_hash.fetch(field) { yield } end def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) encode_with_placeholder_and_null(BSON_ADJUST, encoded) do |encoded| each do |field, value| encoded << value.bson_type encoded << _memo(field) { field.to_bson_key } value.to_bson(encoded) end end end end EVAL end def new_hash_to_bson_integer BSON.module_eval <<-EVAL module Integer def bson_type Integer::INT32_TYPE end end module Hash def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) encode_with_placeholder_and_null(BSON_ADJUST, encoded) do |encoded| each do |field, value| pos = encoded.bytesize encoded << (bson_type = value.bson_type) field.to_bson_key(encoded) mark = encoded.bytesize value.to_bson(encoded) encoded[pos] = Integer::INT64_TYPE if bson_type == Integer::INT32_TYPE && encoded.bytesize - mark == 8 end end end end EVAL end # without extension 0.23 gain, with extension -0.11 gain def test_integer_optimization size = 1024 hash = Hash[*(0..size).to_a.collect{|i| [ ('a' + i.to_s).to_sym, i]}.flatten] method_label_pairs = [ [ method(:old_hash_to_bson), 'Integer optimize none', RESET ], [ method(:new_hash_to_bson_integer), 'Integer optimize int32' ], # Core2 user: 68.2, base: 88.1, gain: 0.23 ] benchmark_methods_with_gc(4_000, method_label_pairs) { hash.to_bson } end def test_symbol_key_optimization size = 1024 hash = Hash[*(0..size).to_a.collect{|i| [ ('a' + i.to_s).to_sym, i]}.flatten] method_label_pairs = [ [ method(:old_hash_to_bson), 'Symbol key optimize none', RESET ], [ method(:new_hash_to_bson_v0), 'Symbol key optimize hash key v0' ], # Xeon user: 33.4, base: 35.9, gain: 0.07 [ method(:new_hash_to_bson_v1), 'Symbol key optimize hash key v1' ] # Xeon user: 26.4, base: 35.9, gain: 0.26 ] benchmark_methods_with_gc(2_000, method_label_pairs) { hash.to_bson } end def test_string_key_optimization size = 1024 hash = Hash[*(0..size).to_a.collect{|i| [ ('a' + i.to_s), i]}.flatten] method_label_pairs = [ [ method(:old_hash_to_bson), 'Symbol key optimize none', RESET ], [ method(:new_hash_to_bson_v0), 'Symbol key optimize hash key v0' ], # Xeon user: 34.5, base: 32.6, gain: -0.06 [ method(:new_hash_to_bson_v1), 'Symbol key optimize hash key v1' ] # Xeon user: 27.5, base: 32.6, gain: 0.15 ] benchmark_methods_with_gc(2_000, method_label_pairs) { hash.to_bson } end def old_time_to_bson BSON.module_eval <<-EVAL module Time def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) encoded << [ (to_f * 1000.0).to_i ].pack(Int64::PACK) end end EVAL end def new_time_to_bson BSON.module_eval <<-EVAL module Time def to_bson(encoded = ''.force_encoding(BINARY), hint = nil) encoded << [ (sec * 1000 + usec / 1000) ].pack(Int64::PACK) end end EVAL end def test_time_to_bson_optimization t = Time.now method_label_pairs = [ [ method(:old_time_to_bson), 'time to_bson optimize none' ], [ method(:new_time_to_bson), 'time to_bson optimize sec usec', RESET ] # Core2 user: 29.5, base: 29.0, gain: -0.02 ] benchmark_methods_with_gc(10_000_000, method_label_pairs) { t.to_bson } end def old_hash_from_bson BSON.module_eval <<-EVAL module Hash def from_bson(bson) hash = new bson.read(4) # Swallow the first four bytes. while (type = bson.readbyte.chr) != NULL_BYTE field = bson.gets(NULL_BYTE).from_bson_string.chop! hash[field] = Registry.get(type).from_bson(bson) end hash end end EVAL end def new_hash_from_bson BSON.module_eval <<-EVAL module Hash def from_bson(bson) hash = new bson.seek(4, IO::SEEK_CUR) # Swallow the first four bytes. while (type = bson.readbyte.chr) != NULL_BYTE field = bson.gets(NULL_BYTE).from_bson_string.chop! hash[field] = Registry.get(type).from_bson(bson) end hash end end EVAL end #review with just op, without hash overhead, check allocation def test_seek size = 1 hash = Hash[*(0..size).to_a.collect{|i| [ ('a' + i.to_s), i.to_s]}.flatten] method_label_pairs = [ [ method(:old_hash_from_bson), 'Encode bson optimize none', RESET ], [ method(:new_hash_from_bson), 'Encode bson optimize seek' ] # Xeon user: 28.2, base: 28.3, gain: 0.00 ] benchmark_methods_with_gc(2_000_000, method_label_pairs) { hash.to_bson } end def old_integer_bson_int32? BSON.module_eval <<-EVAL module Integer def bson_int32? (MIN_32BIT <= self) && (self <= MAX_32BIT) end end EVAL end def new_integer_bson_int32? BSON.module_eval <<-EVAL module Integer @@FIXNUM_HIGHBITS32 = (-1 << 32) def bson_int32? (self & @@FIXNUM_HIGHBITS32) == 0 end end EVAL end def test_bson_int32? method_label_pairs = [ [ method(:old_integer_bson_int32?), 'Integer#bson_int32? old', RESET ], [ method(:new_integer_bson_int32?), 'Integer#bson_int32? new' ] # user: 34.9, base: 21.4, gain: -0.63 ] benchmark_methods_with_gc(100_000_000, method_label_pairs) {|i| i.bson_int32? } end # Statistics and Ruby-prof profiling -------------------------------------------------------------------------------- # pure Ruby - Core2 #utime: 13.92, allocated: 10, label: "BSON::CodeWithScope" #utime: 6.12, allocated: 4, label: "Hash" #utime: 6.11, allocated: 4, label: "BSON::Document" #utime: 4.61, allocated: 5, label: "Regexp" #utime: 4.09, allocated: 4, label: "Array" #utime: 3.70, allocated: 4, label: "Symbol" #utime: 3.50, allocated: 10, label: "Bignum" #utime: 3.27, allocated: 3, label: "BSON::Code" #utime: 3.21, allocated: 3, label: "String" #utime: 2.54, allocated: 5, label: "Time" #utime: 2.08, allocated: 2, label: "BSON::Binary" #utime: 1.57, allocated: 0, label: "BSON::Timestamp" #utime: 1.04, allocated: 2, label: "Float" #utime: 0.93, allocated: 0, label: "Fixnum" #utime: 0.42, allocated: 0, label: "BSON::ObjectId" #utime: 0.29, allocated: 0, label: "TrueClass" #utime: 0.29, allocated: 0, label: "FalseClass" #utime: 0.19, allocated: 0, label: "BSON::MinKey" #utime: 0.19, allocated: 0, label: "BSON::MaxKey" #utime: 0.19, allocated: 0, label: "NilClass" #utime: 0.19, allocated: 0, label: "BSON::Undefined" # with C extension - Core2 #utime: 6.12, allocated: 6, label: "BSON::CodeWithScope" #utime: 3.70, allocated: 7, label: "Regexp" #utime: 3.17, allocated: 3, label: "Hash" #utime: 3.16, allocated: 3, label: "BSON::Document" #utime: 1.89, allocated: 3, label: "Symbol" #utime: 1.89, allocated: 2, label: "Array" #utime: 1.53, allocated: 2, label: "BSON::Code" #utime: 1.47, allocated: 2, label: "String" #utime: 1.30, allocated: 3, label: "Time" #utime: 0.97, allocated: 0, label: "BSON::Binary" #utime: 0.57, allocated: 0, label: "Bignum" #utime: 0.38, allocated: 0, label: "BSON::ObjectId" #utime: 0.38, allocated: 0, label: "BSON::Timestamp" #utime: 0.29, allocated: 0, label: "Fixnum" #utime: 0.22, allocated: 0, label: "Float" #utime: 0.21, allocated: 0, label: "FalseClass" #utime: 0.20, allocated: 0, label: "TrueClass" #utime: 0.20, allocated: 0, label: "BSON::MaxKey" #utime: 0.20, allocated: 0, label: "BSON::MinKey" #utime: 0.20, allocated: 0, label: "BSON::Undefined" #utime: 0.19, allocated: 0, label: "NilClass" def test_to_bson_object_allocation count = 1_000_000 t = Time.now expression = [ Array[1], BSON::Binary.new("xyzzy"), BSON::Code.new("new Object;"), BSON::CodeWithScope.new("new Object;", {x: 1}), BSON::Document['x', 1], false, 3.14159, Hash['x', 1], 2**31 - 1, 2**63 - 1, BSON::MaxKey.new, BSON::MinKey.new, nil, BSON::ObjectId.new, /xyzzy/, 'xyzzy', :xyzzy, Time.now, BSON::Timestamp.new(t.sec, t.usec), true, BSON::Undefined.new ] result = expression.collect do |x| htms, allocated = gc_allocated do tms = Benchmark.measure(x.class.name) do encoded = ''.force_encoding(BSON::BINARY) count.times { x.to_bson(encoded); encoded.clear } end Hash[*[:label, :utime, :stime, :cutime, :cstime, :real].zip(tms.to_a).flatten] end htms.merge!({allocated: allocated, count: count}) end result.sort!{|a,b| b[:utime] <=> a[:utime]} result.each do |h| puts "utime: #{'%.2f' % h[:utime]}, allocated: #{'%2d' % (h[:allocated]/h[:count])}, label: #{h[:label].inspect}" end end def doc_stats(tally, obj) tally[obj.class.name] += 1 case obj.class.name when 'Array'; obj.each {|elem| doc_stats(tally, elem) } when 'FalseClass'; return when 'Fixnum'; return when 'Float'; return when 'Hash'; obj.each {|elem| doc_stats(tally, elem) } when 'NilClass'; return when 'String'; return when 'TrueClass'; return else p obj.class; exit end end #0.44 String 811731 #0.35 Array 646586 #0.07 NilClass 120515 #0.06 Fixnum 120181 #0.05 FalseClass 89655 #0.02 Hash 44144 #0.01 TrueClass 18245 #0.00 Float 996 #objects: 1852053 #objects/doc: 185 def test_doc_stats json_filename = '../../training/data/sampledata/twitter.json' line_limit = 10_000 twitter = nil File.open(json_filename, 'r') do |f| twitter = line_limit.times.collect { JSON.parse(f.gets) } end tally = Hash.new(0) doc_stats(tally, twitter) obj_count = tally.inject(0){|sum, elem| sum + elem[1]} tally = tally.to_a.sort{|a,b| b[1] <=> a[1]} tally.each {|a| puts "#{'%.2f' % (a[1].to_f / obj_count.to_f)} #{a[0]} #{a[1]}" } puts "objects: #{obj_count}" puts "objects/doc: #{obj_count/line_limit}" end def get_twitter_data(line_limit, bson) json_filename = '../../training/data/sampledata/twitter.json' File.open(json_filename, 'r') do |f| f.readlines[0..line_limit].collect {|line| doc = JSON.parse(line); bson ? StringIO.new(doc.to_bson) : doc } end end def test_encode_twitter twitter = get_twitter_data(-1, false) allocated = nil Benchmark.bm(@label_width) do |bench| bench.report(__method__) do result, allocated = gc_allocated do twitter.each {|doc| doc.to_bson } end end end puts "allocated: #{allocated} allocated/line: #{allocated/twitter.size}" end def test_decode_twitter twitter = get_twitter_data(-1, false) allocated = nil Benchmark.bm(@label_width) do |bench| bench.report(__method__) do result, allocated = gc_allocated do twitter = get_twitter_data(-1, true) end end end puts "allocated: #{allocated} allocated/line: #{allocated/twitter.size}" end def ruby_prof(label, bson, file_name) allocated = nil line_limit = nil profile = nil Benchmark.bm(@label_width) do |bench| bench.report(label) do result, allocated = gc_allocated do RubyProf.start line_limit = yield profile = RubyProf.stop end end end puts "allocated: #{allocated} allocated/line: #{allocated/line_limit}" File.open(file_name, 'w') do |f| RubyProf::FlatPrinter.new(profile).print(f) RubyProf::GraphPrinter.new(profile).print(f, {}) end end def test_encode_ruby_prof twitter = get_twitter_data(10_000, false) ruby_prof('test encode ruby prof', false, 'encode-ruby-prof.out') do twitter.each {|doc| doc.to_bson } twitter.size end end def test_decode_ruby_prof twitter = get_twitter_data(10_000, true) ruby_prof('test decode ruby prof', true, 'decode-ruby-prof.out') do twitter.each {|io| io.rewind; Hash.from_bson(io) } twitter.size end end end bson-ruby-4.15.0/release.sh000077500000000000000000000021551423026727100155070ustar00rootroot00000000000000#!/bin/sh set -e NAME=bson RELEASE_NAME=bson-ruby-release VERSION_REQUIRE=bson/version VERSION_CONSTANT_NAME=BSON::VERSION if ! test -f gem-private_key.pem; then echo "gem-private_key.pem missing - cannot release" 1>&2 exit 1 fi VERSION=`ruby -Ilib -r$VERSION_REQUIRE -e "puts $VERSION_CONSTANT_NAME"` echo "Releasing $NAME $VERSION" echo for variant in mri jruby; do docker build -f release/$variant/Dockerfile -t $RELEASE_NAME-$variant . docker kill $RELEASE_NAME-$variant || true docker container rm $RELEASE_NAME-$variant || true docker run -d --name $RELEASE_NAME-$variant -it $RELEASE_NAME-$variant docker exec $RELEASE_NAME-$variant /app/release/$variant/build.sh if test $variant = jruby; then docker cp $RELEASE_NAME-$variant:/app/$NAME-$VERSION-java.gem . else docker cp $RELEASE_NAME-$variant:/app/$NAME-$VERSION.gem . fi docker kill $RELEASE_NAME-$variant done echo echo Built: $NAME-$VERSION.gem echo Built: $NAME-$VERSION-java.gem echo git tag -a v$VERSION -m "Tagging release: $VERSION" git push origin v$VERSION gem push $NAME-$VERSION.gem gem push $NAME-$VERSION-java.gem bson-ruby-4.15.0/release/000077500000000000000000000000001423026727100151455ustar00rootroot00000000000000bson-ruby-4.15.0/release/jruby/000077500000000000000000000000001423026727100163005ustar00rootroot00000000000000bson-ruby-4.15.0/release/jruby/Dockerfile000066400000000000000000000006661423026727100203020ustar00rootroot00000000000000FROM debian:9 ENV DEBIAN_FRONTEND=noninteractive # Must use JDK 8 for building release packages to avoid this error: # java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer; # https://github.com/hazelcast/hazelcast/issues/14214 RUN apt-get update && \ apt-get -y install openjdk-8-jdk ruby git curl make g++ WORKDIR /rubies COPY release/jruby/install.sh /rubies/ RUN /rubies/install.sh WORKDIR /app COPY . . bson-ruby-4.15.0/release/jruby/build.sh000077500000000000000000000003051423026727100177340ustar00rootroot00000000000000#!/bin/bash set -e export PATH=/rubies/jruby/bin:$PATH gem install bundler --no-document rm -f *.lock rm -f *.gem bundle install --without=test rake build /app/release/verify-signature.sh *.gem bson-ruby-4.15.0/release/jruby/install.sh000077500000000000000000000002641423026727100203070ustar00rootroot00000000000000#!/bin/bash set -e mkdir -p /rubies cd /rubies git clone https://github.com/rbenv/ruby-build.git PREFIX=/usr ./ruby-build/install.sh ruby-build -v jruby-9.2.11.1 /rubies/jruby bson-ruby-4.15.0/release/mri/000077500000000000000000000000001423026727100157345ustar00rootroot00000000000000bson-ruby-4.15.0/release/mri/Dockerfile000066400000000000000000000002341423026727100177250ustar00rootroot00000000000000FROM debian:10 ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ apt-get -y install git ruby-bundler make gcc ruby-dev WORKDIR /app COPY . . bson-ruby-4.15.0/release/mri/build.sh000077500000000000000000000001761423026727100173760ustar00rootroot00000000000000#!/bin/bash set -e rm -f *.lock rm -f *.gem bundle install --without=test rake build /app/release/verify-signature.sh *.gem bson-ruby-4.15.0/release/verify-signature.sh000077500000000000000000000015011423026727100210040ustar00rootroot00000000000000#!/bin/bash set -ex gem="$1" if test -z "$gem"; then echo "Usage: `basename $0` /path/to/built.gem" 1>&2 exit 1 fi gem cert --add gem-public_cert.pem gem install -P HighSecurity $gem exit # The verification below does not work. # https://github.com/rubygems/rubygems/issues/3680 # https://docs.ruby-lang.org/en/2.7.0/Gem/Security.html tar xf $gem # Grab the public key from the gemspec gem spec $gem cert_chain | \ ruby -ryaml -e 'puts YAML.load(STDIN)' > actual_public_key.crt for file in data.tar.gz metadata.tar.gz; do # Generate a SHA1 hash of the data.tar.gz openssl dgst -sha1 < $file > actual.hash # Verify the signature openssl rsautl -verify -inkey actual_public_key.crt -certin \ -in $file.sig > signed.hash # Compare your hash to the verified hash diff -s actual.hash signed.hash done bson-ruby-4.15.0/spec/000077500000000000000000000000001423026727100144575ustar00rootroot00000000000000bson-ruby-4.15.0/spec/README.md000066400000000000000000000005111423026727100157330ustar00rootroot00000000000000# Running BSON Ruby Tests ## Quick Start The test suite requires shared tooling that is stored in a separate repository and is referenced as a submodule. After checking out the desired bson-ruby branch, check out the matching submodules: git submodule init git submodule update Then, to run the test suite: rake bson-ruby-4.15.0/spec/bson/000077500000000000000000000000001423026727100154205ustar00rootroot00000000000000bson-ruby-4.15.0/spec/bson/array_spec.rb000066400000000000000000000122211423026727100200730ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe Array do describe "#to_bson/#from_bson" do let(:type) { 4.chr } let(:obj) {[ "one", "two" ]} let(:bson) do BSON::Document["0", "one", "1", "two"].to_bson.to_s end it_behaves_like "a bson element" it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" context "when the array has documents containing invalid keys" do let(:obj) do [ { "$testing" => "value" } ] end context "when validating keys" do context "when validating globally" do before do BSON::Config.validating_keys = true end after do BSON::Config.validating_keys = false end it "raises an error" do expect { obj.to_bson }.to raise_error(BSON::String::IllegalKey) end end context "when validating locally" do it "raises an error" do expect { obj.to_bson(BSON::ByteBuffer.new, true) }.to raise_error(BSON::String::IllegalKey) end context "when serializing different types" do let(:obj) do [ BSON::Binary.new("testing", :generic), BSON::Code.new("this.value = 5"), BSON::CodeWithScope.new("this.value = val", "test"), Date.new(2012, 1, 1), Time.utc(2012, 1, 1), DateTime.new(2012, 1, 1, 0, 0, 0), false, 1.2332, Integer::MAX_32BIT - 1, BSON::ObjectId.new, /\W+/i, 'a string', :a_symbol, Time.utc(2012, 1, 1, 0, 0, 0), BSON::Timestamp.new(1, 10), true, { "$testing" => "value" } ] end it "raises an error" do expect { obj.to_bson(BSON::ByteBuffer.new, true) }.to raise_error(BSON::String::IllegalKey) end end end end context "when not validating keys" do let(:bson) do BSON::Document["0", { "$testing" => "value" }].to_bson.to_s end it "serializes the hash" do expect(obj.to_bson.to_s).to eq(bson) end context "when serializing different types" do let(:obj) do [ BSON::Binary.new("testing", :generic), BSON::Code.new("this.value = 5"), BSON::CodeWithScope.new("this.value = val", "test"), Date.new(2012, 1, 1), Time.utc(2012, 1, 1), DateTime.new(2012, 1, 1, 0, 0, 0), false, 1.2332, Integer::MAX_32BIT - 1, BSON::ObjectId.new, /\W+/i, 'a string', :a_symbol, Time.utc(2012, 1, 1, 0, 0, 0), BSON::Timestamp.new(1, 10), true, { "$testing" => "value" } ] end it "serializes the hash" do expect(obj.to_bson.length).to eq(252) end end end end context 'when array contains value of an unserializable class' do class ArraySpecUnserializableClass end let(:obj) do [ArraySpecUnserializableClass.new] end it 'raises UnserializableClass' do lambda do obj.to_bson end.should raise_error(BSON::Error::UnserializableClass, # C extension does not provide element position in the exception message. /(Array element at position 0|Value) does not define its BSON serialized type:.*ArraySpecUnserializableClass/) end end end describe "#to_bson_normalized_value" do let(:klass) { Class.new(Hash) } let(:obj) {[ Foo.new ]} before(:each) { stub_const "Foo", klass } it "does not mutate the receiver" do obj.to_bson_normalized_value expect(obj.first.class).to eq(Foo) end end describe "#to_bson_object_id" do context "when the array has 12 elements" do let(:array) do [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ] end let(:converted) do array.to_bson_object_id end it "returns the array as a string" do expect(converted).to eq(array.pack("C*")) end end context "when the array does not have 12 elements" do it "raises an exception" do expect { [ 1 ].to_bson_object_id }.to raise_error(BSON::ObjectId::Invalid) end end end end bson-ruby-4.15.0/spec/bson/big_decimal_spec.rb000066400000000000000000000173241423026727100212050ustar00rootroot00000000000000# Copyright (C) 2016-2021 MongoDB Inc. # # 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. require "spec_helper" describe BSON::BigDecimal do describe '#from_bson' do shared_examples_for 'a BSON::BigDecimal deserializer' do let(:decimal128) do BSON::Decimal128.new(argument) end let(:deserialized_big_decimal) do BigDecimal.from_bson(decimal128.to_bson) end let(:deserialized_decimal128) do BSON::Decimal128.from_bson(decimal128.to_bson) end it 'deserializes Decimal128 encoded bson correctly' do if deserialized_decimal128.to_s == "NaN" expect(deserialized_big_decimal.nan?).to be true else expect(deserialized_big_decimal).to eq(deserialized_decimal128.to_big_decimal) end end end context 'when Infinity is passed' do let(:argument) { "Infinity" } it_behaves_like 'a BSON::BigDecimal deserializer' end context 'when -Infinity is passed' do let(:argument) { "-Infinity" } it_behaves_like 'a BSON::BigDecimal deserializer' end context 'when NaN is passed' do let(:argument) { "NaN" } it_behaves_like 'a BSON::BigDecimal deserializer' end context 'when -NaN is passed' do let(:argument) { "-NaN" } it_behaves_like 'a BSON::BigDecimal deserializer' end context 'when SNaN is passed' do let(:argument) { "SNaN" } it_behaves_like 'a BSON::BigDecimal deserializer' end context 'when -SNaN is passed' do let(:argument) { "SNaN" } it_behaves_like 'a BSON::BigDecimal deserializer' end context 'when -0 is passed' do let(:argument) { "-0" } it_behaves_like 'a BSON::BigDecimal deserializer' end context 'when a positive integer is passed' do let(:argument) { "12" } it_behaves_like 'a BSON::BigDecimal deserializer' end context 'when a negative integer is passed' do let(:argument) { "-12" } it_behaves_like 'a BSON::BigDecimal deserializer' end context 'when a positive float is passed' do let(:argument) { "0.12345" } it_behaves_like 'a BSON::BigDecimal deserializer' end context 'when a negative float is passed' do let(:argument) { "-0.12345" } it_behaves_like 'a BSON::BigDecimal deserializer' end context 'when a large positive integer is passed' do let(:argument) { "1234567890123456789012345678901234" } it_behaves_like 'a BSON::BigDecimal deserializer' end context 'when a large negative integer is passed' do let(:argument) { "-1234567890123456789012345678901234" } it_behaves_like 'a BSON::BigDecimal deserializer' end end describe "#to_bson" do shared_examples_for 'a BSON::BigDecimal serializer' do let(:decimal128) do BSON::Decimal128.new(BigDecimal(argument).to_s) end let(:decimal_128_bson) do decimal128.to_bson end let(:big_decimal_bson) do BigDecimal(argument).to_bson end it 'serializes BigDecimals correctly' do expect(decimal_128_bson.to_s).to eq(big_decimal_bson.to_s) end end context 'when Infinity is passed' do let(:argument) { "Infinity" } it_behaves_like 'a BSON::BigDecimal serializer' end context 'when -Infinity is passed' do let(:argument) { "-Infinity" } it_behaves_like 'a BSON::BigDecimal serializer' end context 'when NaN is passed' do let(:argument) { "NaN" } it_behaves_like 'a BSON::BigDecimal serializer' end context 'when -0 is passed' do let(:argument) { "-0" } it_behaves_like 'a BSON::BigDecimal serializer' end context 'when a positive integer is passed' do let(:argument) { "12" } it_behaves_like 'a BSON::BigDecimal serializer' end context 'when a negative integer is passed' do let(:argument) { "-12" } it_behaves_like 'a BSON::BigDecimal serializer' end context 'when a positive float is passed' do let(:argument) { "0.12345" } it_behaves_like 'a BSON::BigDecimal serializer' end context 'when a negative float is passed' do let(:argument) { "-0.12345" } it_behaves_like 'a BSON::BigDecimal serializer' end context 'when a large positive integer is passed' do let(:argument) { "1234567890123456789012345678901234" } it_behaves_like 'a BSON::BigDecimal serializer' end context 'when a large negative integer is passed' do let(:argument) { "-1234567890123456789012345678901234" } it_behaves_like 'a BSON::BigDecimal serializer' end context "when passing an out of range Decimal128" do let(:argument) { "1E1000000" } it "raises an error" do expect do BigDecimal(argument).to_bson end.to raise_error(BSON::Decimal128::InvalidRange) end end context "when passing a number with too much precision for Decimal128" do let(:argument) { "1.000000000000000000000000000000000000000000000000001" } it "raises an error" do expect do BigDecimal(argument).to_bson end.to raise_error(BSON::Decimal128::UnrepresentablePrecision) end end end describe "#from_bson/#to_bson" do shared_examples_for 'a BSON::BigDecimal round trip' do let(:big_decimal) do BigDecimal(argument) end let(:big_decimal_bson) do big_decimal.to_bson end let(:deserialized_big_decimal) do BigDecimal.from_bson(big_decimal_bson) end it 'serializes BigDecimals correctly' do if big_decimal.nan? expect(deserialized_big_decimal.nan?).to be true else expect(deserialized_big_decimal).to eq(big_decimal) end end end context 'when Infinity is passed' do let(:argument) { "Infinity" } it_behaves_like 'a BSON::BigDecimal round trip' end context 'when -Infinity is passed' do let(:argument) { "-Infinity" } it_behaves_like 'a BSON::BigDecimal round trip' end context 'when NaN is passed' do let(:argument) { "NaN" } it_behaves_like 'a BSON::BigDecimal round trip' end context 'when -0 is passed' do let(:argument) { "-0" } it_behaves_like 'a BSON::BigDecimal round trip' end context 'when a positive integer is passed' do let(:argument) { "12" } it_behaves_like 'a BSON::BigDecimal round trip' end context 'when a negative integer is passed' do let(:argument) { "-12" } it_behaves_like 'a BSON::BigDecimal round trip' end context 'when a positive float is passed' do let(:argument) { "0.12345" } it_behaves_like 'a BSON::BigDecimal round trip' end context 'when a negative float is passed' do let(:argument) { "-0.12345" } it_behaves_like 'a BSON::BigDecimal round trip' end context 'when a large positive integer is passed' do let(:argument) { "1234567890123456789012345678901234" } it_behaves_like 'a BSON::BigDecimal round trip' end context 'when a large negative integer is passed' do let(:argument) { "-1234567890123456789012345678901234" } it_behaves_like 'a BSON::BigDecimal round trip' end end end bson-ruby-4.15.0/spec/bson/binary_spec.rb000066400000000000000000000201621423026727100202440ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" require "base64" describe BSON::Binary do let(:testing1) { described_class.new("testing") } let(:testing2) { described_class.new("testing") } let(:not_testing) { described_class.new("not testing") } describe "#eql?" do context "for two equal objects" do it "returns true" do expect(testing1).to eql(testing2) end end context "for two different objects" do it "returns false" do expect(testing1).not_to eql(not_testing) end end end describe "#hash" do context "for two equal objects" do it "is the same" do expect(testing1.hash).to eq(testing2.hash) end end context "for two different objects" do it "is different" do expect(testing1.hash).not_to eq(not_testing.hash) end end end let(:hash) do { testing1 => "my value" } end it "can be used as Hash key" do expect(hash[testing2]).to eq("my value") expect(hash[not_testing]).to be_nil end describe "#as_json" do let(:object) do described_class.new("testing", :user) end it "returns the binary data plus type" do expect(object.as_json).to eq( { "$binary" => {'base64' => Base64.encode64("testing").strip, "subType" => '80' }} ) end it_behaves_like "a JSON serializable object" end describe "#initialize" do context 'when type is not given' do let(:obj) { described_class.new('foo') } it 'defaults to generic type' do expect(obj.type).to eq(:generic) end end context "when he type is invalid" do it "raises an error" do expect { described_class.new("testing", :error) }.to raise_error { |error| expect(error).to be_a(BSON::Binary::InvalidType) expect(error.message).to match /is not a valid binary type/ } end end end describe '#inspect' do let(:object) do described_class.new('testing123', :user) end it 'returns the truncated data and type' do expect(object.inspect).to eq("") end context 'with other encoding' do let(:object) do described_class.new("\x1F\x8B\b\x00\fxpU\x00\x03\xED\x1C\xDBv\xDB6\xF2\xBD_\x81UN\x9A\xE6T\x96H\xDD-\xDBjR7\xDD\xA6mR\x9F:m\xB7".force_encoding(Encoding::BINARY), :user) end it 'returns the truncated data and type' do expect(object.inspect).to eq("") end it 'is not binary' do # As long as the default Ruby encoding is not binary, the inspected # string should also not be in the binary encoding (it should be # in one of the text encodings, but which one could depend on # the Ruby runtime environment). expect(object.inspect.encoding).not_to eq(Encoding::BINARY) end end end describe '#from_bson' do let(:buffer) { BSON::ByteBuffer.new(bson) } let(:obj) { described_class.from_bson(buffer) } let(:bson) { "#{5.to_bson}#{0.chr}hello".force_encoding('BINARY') } it 'sets data encoding to binary' do expect(obj.data.encoding).to eq(Encoding.find('BINARY')) end context 'when binary subtype is supported' do let(:bson) { [3, 0, 0, 0, 1].map(&:chr).join.force_encoding('BINARY') + 'foo' } it 'works' do obj.should be_a(described_class) obj.type.should be :function end end context 'when binary subtype is not supported' do let(:bson) { [3, 0, 0, 0, 16].map(&:chr).join.force_encoding('BINARY') + 'foo' } it 'raises an exception' do lambda do obj end.should raise_error(BSON::Error::UnsupportedBinarySubtype, /BSON data contains unsupported binary subtype 0x10/) end end end describe "#to_bson/#from_bson" do let(:type) { 5.chr } it_behaves_like "a bson element" context "when the type is :generic" do let(:obj) { described_class.new("testing") } let(:bson) { "#{7.to_bson}#{0.chr}testing" } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context "when the type is :function" do let(:obj) { described_class.new("testing", :function) } let(:bson) { "#{7.to_bson}#{1.chr}testing" } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context "when the type is :old" do let(:obj) { described_class.new("testing", :old) } let(:bson) { "#{11.to_bson}#{2.chr}#{7.to_bson}testing" } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context "when the type is :uuid_old" do let(:obj) { described_class.new("testing", :uuid_old) } let(:bson) { "#{7.to_bson}#{3.chr}testing" } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context "when the type is :uuid" do let(:obj) { described_class.new("testing", :uuid) } let(:bson) { "#{7.to_bson}#{4.chr}testing" } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context "when the type is :md5" do let(:obj) { described_class.new("testing", :md5) } let(:bson) { "#{7.to_bson}#{5.chr}testing" } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context "when the type is :user" do let(:obj) { described_class.new("testing", :user) } let(:bson) { "#{7.to_bson}#{128.chr}testing" } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context "when the type is :cyphertext" do let(:obj) { described_class.new("testing", :ciphertext) } let(:bson) { "#{7.to_bson}#{6.chr}testing" } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context 'when given binary string' do let(:obj) { described_class.new("\x00\xfe\xff".force_encoding('BINARY')) } let(:bson) { "#{3.to_bson}#{0.chr}\x00\xfe\xff".force_encoding('BINARY') } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context 'when given a frozen string' do let(:str) { "\x00\xfe\xff".force_encoding('BINARY').freeze } let(:obj) { described_class.new(str) } let(:bson) { "#{3.to_bson}#{0.chr}\x00\xfe\xff".force_encoding('BINARY') } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end end describe '#to_uuid' do let(:obj) { described_class.new("\x00" * 16, :uuid) } it 'accepts symbol representation' do expect(obj.to_uuid(:standard)).to eq('00000000-0000-0000-0000-000000000000') end it 'rejects string representation' do expect do obj.to_uuid('standard') end.to raise_error(ArgumentError, /Representation must be given as a symbol/) end end describe '#from_uuid' do let(:uuid) { '00000000-0000-0000-0000000000000000' } it 'accepts symbol representation' do obj = described_class.from_uuid(uuid, :standard) expect(obj.data).to eq("\x00" * 16) end it 'rejects string representation' do expect do described_class.from_uuid(uuid, 'standard') end.to raise_error(ArgumentError, /Representation must be given as a symbol/) end end end bson-ruby-4.15.0/spec/bson/binary_uuid_spec.rb000066400000000000000000000151021423026727100212700ustar00rootroot00000000000000# Copyright (C) 2019-2020 MongoDB Inc. # # 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. require "spec_helper" require "base64" describe "BSON::Binary - UUID spec tests" do def make_binary(uuid_hex_str, type) uuid_binary_str = uuid_hex_str.scan(/../).map(&:hex).map(&:chr).join BSON::Binary.new(uuid_binary_str, type) end describe 'explicit encoding' do let(:uuid_str) { '00112233-4455-6677-8899-aabbccddeeff' } shared_examples_for 'creates binary' do it 'creates subtype 4 binary' do expect(binary.type).to eq(expected_type) end it 'creates binary with correct value' do expect(binary.data).to eq(expected_hex_value.scan(/../).map(&:hex).map(&:chr).join) end end context 'no representation' do let(:binary) { BSON::Binary.from_uuid(uuid_str) } let(:expected_type) { :uuid } let(:expected_hex_value) { '00112233445566778899AABBCCDDEEFF' } it_behaves_like 'creates binary' end context 'standard representation' do let(:binary) { BSON::Binary.from_uuid(uuid_str, :standard) } let(:expected_type) { :uuid } let(:expected_hex_value) { '00112233445566778899AABBCCDDEEFF' } it_behaves_like 'creates binary' end context 'csharp legacy representation' do let(:binary) { BSON::Binary.from_uuid(uuid_str, :csharp_legacy) } let(:expected_type) { :uuid_old } let(:expected_hex_value) { '33221100554477668899AABBCCDDEEFF' } it_behaves_like 'creates binary' end context 'java legacy representation' do let(:binary) { BSON::Binary.from_uuid(uuid_str, :java_legacy) } let(:expected_type) { :uuid_old } let(:expected_hex_value) { '7766554433221100FFEEDDCCBBAA9988' } it_behaves_like 'creates binary' end context 'python legacy representation' do let(:binary) { BSON::Binary.from_uuid(uuid_str, :python_legacy) } let(:expected_type) { :uuid_old } let(:expected_hex_value) { '00112233445566778899AABBCCDDEEFF' } it_behaves_like 'creates binary' end end describe 'explicit decoding' do context ':uuid, standard encoded' do let(:binary) { make_binary("00112233445566778899AABBCCDDEEFF", :uuid) } it 'decodes without arguments' do expect(binary.to_uuid.gsub('-', '').upcase).to eq("00112233445566778899AABBCCDDEEFF") end it 'decodes as standard' do expect(binary.to_uuid(:standard).gsub('-', '').upcase).to eq("00112233445566778899AABBCCDDEEFF") end it 'does not decode as csharp legacy' do expect do binary.to_uuid(:csharp_legacy) end.to raise_error(ArgumentError, /Binary of type :uuid can only be stringified to :standard representation/) end it 'does not decode as java legacy' do expect do binary.to_uuid(:java_legacy) end.to raise_error(ArgumentError, /Binary of type :uuid can only be stringified to :standard representation/) end it 'does not decode as python legacy' do expect do binary.to_uuid(:python_legacy) end.to raise_error(ArgumentError, /Binary of type :uuid can only be stringified to :standard representation/) end end shared_examples_for 'a legacy uuid' do it 'does not decode without arguments' do expect do binary.to_uuid end.to raise_error(ArgumentError, /Representation must be specified for BSON::Binary objects of type :uuid_old/) end it 'does not decode as standard' do expect do binary.to_uuid(:standard) end.to raise_error(ArgumentError, /BSON::Binary objects of type :uuid_old cannot be stringified to :standard representation/) end end context ':uuid_old, csharp legacy encoded' do let(:binary) { make_binary("33221100554477668899AABBCCDDEEFF", :uuid_old) } it_behaves_like 'a legacy uuid' it 'decodes as csharp legacy' do expect(binary.to_uuid(:csharp_legacy).gsub('-', '').upcase).to eq("00112233445566778899AABBCCDDEEFF") end it 'decodes as java legacy' do expect(binary.to_uuid(:java_legacy).gsub('-', '').upcase).not_to eq("00112233445566778899AABBCCDDEEFF") end it 'decodes as python legacy' do expect(binary.to_uuid(:python_legacy).gsub('-', '').upcase).not_to eq("00112233445566778899AABBCCDDEEFF") end it 'expects four dashes when output as String' do expect(binary.to_uuid(:csharp_legacy)).to eq("00112233-4455-6677-8899-aabbccddeeff") end end context ':uuid_old, java legacy encoded' do let(:binary) { make_binary("7766554433221100FFEEDDCCBBAA9988", :uuid_old) } it_behaves_like 'a legacy uuid' it 'decodes as csharp legacy' do expect(binary.to_uuid(:csharp_legacy).gsub('-', '').upcase).not_to eq("00112233445566778899AABBCCDDEEFF") end it 'decodes as java legacy' do expect(binary.to_uuid(:java_legacy).gsub('-', '').upcase).to eq("00112233445566778899AABBCCDDEEFF") end it 'decodes as python legacy' do expect(binary.to_uuid(:python_legacy).gsub('-', '').upcase).not_to eq("00112233445566778899AABBCCDDEEFF") end it 'expects four dashes when output as String' do expect(binary.to_uuid(:java_legacy)).to eq("00112233-4455-6677-8899-aabbccddeeff") end end context ':uuid_old, python legacy encoded' do let(:binary) { make_binary("00112233445566778899AABBCCDDEEFF", :uuid_old) } it_behaves_like 'a legacy uuid' it 'decodes as csharp legacy' do expect(binary.to_uuid(:csharp_legacy).gsub('-', '').upcase).not_to eq("00112233445566778899AABBCCDDEEFF") end it 'decodes as java legacy' do expect(binary.to_uuid(:java_legacy).gsub('-', '').upcase).not_to eq("00112233445566778899AABBCCDDEEFF") end it 'decodes as python legacy' do expect(binary.to_uuid(:python_legacy).gsub('-', '').upcase).to eq("00112233445566778899AABBCCDDEEFF") end it 'expects four dashes when output as String' do expect(binary.to_uuid(:python_legacy)).to eq("00112233-4455-6677-8899-aabbccddeeff") end end end end bson-ruby-4.15.0/spec/bson/boolean_spec.rb000066400000000000000000000022271423026727100204010ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::Boolean do describe "::BSON_TYPE" do it "returns 8" do expect(BSON::Boolean::BSON_TYPE).to eq(8.chr) end end describe "#from_bson" do let(:type) { 8.chr } it_behaves_like "a bson element" context "when the boolean is true" do let(:obj) { true } let(:bson) { 1.chr } it_behaves_like "a deserializable bson element" end context "when the boolean is false" do let(:obj) { false } let(:bson) { 0.chr } it_behaves_like "a deserializable bson element" end end end bson-ruby-4.15.0/spec/bson/byte_buffer_read_spec.rb000066400000000000000000000074211423026727100222520ustar00rootroot00000000000000require 'spec_helper' describe BSON::ByteBuffer do describe '#get_byte' do let(:buffer) do described_class.new(BSON::Int32::BSON_TYPE) end let!(:byte) do buffer.get_byte end it 'gets the byte from the buffer' do expect(byte).to eq(BSON::Int32::BSON_TYPE) end it 'increments the read position by 1' do expect(buffer.read_position).to eq(1) end end describe '#get_bytes' do let(:string) do "#{BSON::Int32::BSON_TYPE}#{BSON::Int32::BSON_TYPE}" end let(:buffer) do described_class.new(string) end let!(:bytes) do buffer.get_bytes(2) end it 'gets the bytes from the buffer' do expect(bytes).to eq(string) end it 'increments the position by the length' do expect(buffer.read_position).to eq(string.bytesize) end end describe '#get_cstring' do let(:buffer) do described_class.new("testing#{BSON::NULL_BYTE}") end let!(:string) do buffer.get_cstring end it 'gets the cstring from the buffer' do expect(string).to eq("testing") end it 'increments the position by string length + 1' do expect(buffer.read_position).to eq(8) end end describe '#get_double' do let(:buffer) do described_class.new(12.5.to_bson.to_s) end let!(:double) do buffer.get_double end it 'gets the double from the buffer' do expect(double).to eq(12.5) end it 'increments the read position by 8' do expect(buffer.read_position).to eq(8) end end describe '#get_int32' do let(:buffer) do described_class.new(12.to_bson.to_s) end let!(:int32) do buffer.get_int32 end it 'gets the int32 from the buffer' do expect(int32).to eq(12) end it 'increments the position by 4' do expect(buffer.read_position).to eq(4) end end describe '#get_uint32' do context 'when using 2^32-1' do let(:buffer) do described_class.new(4294967295.to_bson.to_s) end let!(:int32) do buffer.get_uint32 end it 'gets the uint32 from the buffer' do expect(int32).to eq(4294967295) end it 'increments the position by 4' do expect(buffer.read_position).to eq(4) end end context 'when using 2^32-2' do let(:buffer) do described_class.new(4294967294.to_bson.to_s) end let!(:int32) do buffer.get_uint32 end it 'gets the uint32 from the buffer' do expect(int32).to eq(4294967294) end it 'increments the position by 4' do expect(buffer.read_position).to eq(4) end end context 'when using 0' do let(:buffer) do described_class.new(0.to_bson.to_s) end let!(:int32) do buffer.get_uint32 end it 'gets the uint32 from the buffer' do expect(int32).to eq(0) end it 'increments the position by 4' do expect(buffer.read_position).to eq(4) end end end describe '#get_int64' do let(:buffer) do described_class.new((Integer::MAX_64BIT - 1).to_bson.to_s) end let!(:int64) do buffer.get_int64 end it 'gets the int64 from the buffer' do expect(int64).to eq(Integer::MAX_64BIT - 1) end it 'increments the position by 8' do expect(buffer.read_position).to eq(8) end end describe '#get_string' do let(:buffer) do described_class.new("#{8.to_bson.to_s}testing#{BSON::NULL_BYTE}") end let!(:string) do buffer.get_string end it 'gets the string from the buffer' do expect(string).to eq("testing") end it 'increments the position by string length + 5' do expect(buffer.read_position).to eq(12) end end end bson-ruby-4.15.0/spec/bson/byte_buffer_spec.rb000066400000000000000000000121441423026727100212550ustar00rootroot00000000000000require 'spec_helper' describe BSON::ByteBuffer do describe '#allocate' do let(:buffer) do described_class.allocate end it 'allocates a buffer' do expect(buffer).to be_a(BSON::ByteBuffer) end end describe '#length' do context 'empty buffer' do let(:buffer) do described_class.new end it 'is zero' do expect(buffer.length).to eq(0) end end context 'when the byte buffer is initialized with no bytes' do let(:buffer) do described_class.new end context '#put_int32' do before do buffer.put_int32(5) end it 'returns the length of the buffer' do expect(buffer.length).to eq(4) end end end context 'when the byte buffer is initialized with some bytes' do let(:buffer) do described_class.new("#{BSON::Int32::BSON_TYPE}#{BSON::Int32::BSON_TYPE}") end it 'returns the length' do expect(buffer.length).to eq(2) end end context 'after the byte buffer was read from' do let(:buffer) do described_class.new({}.to_bson.to_s) end it 'returns the number of bytes remaining in the buffer' do expect(buffer.length).to eq(5) buffer.get_int32 expect(buffer.length).to eq(1) end end context 'after the byte buffer was converted to string' do shared_examples 'returns the total buffer length' do it 'returns the total buffer length' do expect(buffer.length).to eq(5) buffer.to_s.length.should == 5 expect(buffer.length).to eq(5) end end context 'read buffer' do let(:buffer) do described_class.new({}.to_bson.to_s) end include_examples 'returns the total buffer length' end context 'write buffer' do let(:buffer) do described_class.new.tap do |buffer| buffer.put_bytes('hello') end end include_examples 'returns the total buffer length' end end end describe '#rewind!' do shared_examples_for 'a rewindable buffer' do let(:string) do "#{BSON::Int32::BSON_TYPE}#{BSON::Int32::BSON_TYPE}" end before do buffer.get_bytes(1) buffer.rewind! end it 'resets the read position to 0' do expect(buffer.read_position).to eq(0) end it 'starts subsequent reads at position 0' do expect(buffer.get_bytes(2)).to eq(string) end end context 'when the buffer is instantiated with a string' do let(:buffer) do described_class.new(string) end it_behaves_like 'a rewindable buffer' end context 'when the buffer is instantiated with nothing' do let(:buffer) do described_class.new end before do buffer.put_byte(BSON::Int32::BSON_TYPE).put_byte(BSON::Int32::BSON_TYPE) end it_behaves_like 'a rewindable buffer' end it 'does not change write position' do buffer = described_class.new buffer.put_byte(BSON::Int32::BSON_TYPE) expect(buffer.write_position).to eq(1) buffer.rewind! expect(buffer.write_position).to eq(1) end end describe 'write followed by read' do let(:buffer) do described_class.new end context 'one cycle' do it 'returns the written data' do buffer.put_cstring('hello') buffer.get_cstring.should == 'hello' end end context 'two cycles' do it 'returns the written data' do buffer.put_cstring('hello') buffer.get_cstring.should == 'hello' buffer.put_cstring('world') buffer.get_cstring.should == 'world' end end context 'mixed cycles' do it 'returns the written data' do if BSON::Environment.jruby? pending 'RUBY-2334' end buffer.put_int32(1) buffer.put_int32(2) buffer.get_int32.should == 1 buffer.put_int32(3) buffer.get_int32.should == 2 buffer.get_int32.should == 3 end end end describe '#to_s' do context 'read buffer' do let(:buffer) do described_class.new("\x18\x00\x00\x00*\x00\x00\x00") end it 'returns the data' do buffer.to_s.should == "\x18\x00\x00\x00*\x00\x00\x00" end it 'returns the remaining buffer contents after a read' do buffer.to_s.should == "\x18\x00\x00\x00*\x00\x00\x00" buffer.get_int32.should == 24 buffer.to_s.should == "*\x00\x00\x00" end end context 'write buffer' do let(:buffer) do described_class.new.tap do |buffer| buffer.put_int32(24) end end it 'returns the data' do buffer.to_s.should == "\x18\x00\x00\x00".force_encoding('binary') end it 'returns the complete buffer contents after a write' do buffer.to_s.should == "\x18\x00\x00\x00".force_encoding('binary') buffer.put_int32(42) buffer.to_s.should == "\x18\x00\x00\x00*\x00\x00\x00".force_encoding('binary') end end end end bson-ruby-4.15.0/spec/bson/byte_buffer_write_spec.rb000066400000000000000000000476631423026727100225050ustar00rootroot00000000000000require 'spec_helper' describe BSON::ByteBuffer do let(:buffer) do described_class.new end shared_examples_for 'does not write' do it 'raises ArgumentError' do expect do modified end.to raise_error(ArgumentError) end it 'does not change write position' do expect do modified end.to raise_error(ArgumentError) expect(buffer.write_position).to eq(0) end end describe '#put_byte' do let(:modified) do buffer.put_byte(BSON::Int32::BSON_TYPE) end it 'appends the byte to the byte buffer' do expect(modified.to_s).to eq(BSON::Int32::BSON_TYPE.chr) end it 'increments the write position by 1' do expect(modified.write_position).to eq(1) end context 'when it receives a numeric value' do it 'raises the ArgumentError exception' do expect{buffer.put_byte(1)}.to raise_error(ArgumentError) end end context 'when it receives a nil value' do it 'raises the ArgumentError exception' do expect{buffer.put_byte(nil)}.to raise_error(ArgumentError) end end context 'when given a string of length > 1' do let(:modified) do buffer.put_byte('xx') end it_behaves_like 'does not write' end context 'when given a string of length 0' do let(:modified) do buffer.put_byte('') end it_behaves_like 'does not write' end context 'when byte is not valid utf-8' do let(:string) do Utils.make_byte_string([254]).freeze end let(:modified) do buffer.put_byte(string) end it 'writes the byte' do expect(modified.to_s).to eq(string) end end end describe '#put_bytes' do let(:modified) do buffer.put_bytes(BSON::Int32::BSON_TYPE) buffer end it 'increments the write position by 1' do expect(modified.write_position).to eq(1) end context 'when it receives a numeric value' do it 'raises the ArgumentError exception' do expect{buffer.put_bytes(1)}.to raise_error(ArgumentError) end end context 'when it receives a nil value' do it 'raises the ArgumentError exception' do expect{buffer.put_bytes(nil)}.to raise_error(ArgumentError) end end context 'when given a string with null bytes' do let(:byte_str) { [0, 239, 254, 0].map(&:chr).join } let(:modified) do buffer.put_bytes(byte_str) end before do expect(buffer.write_position).to eq(0) expect(byte_str.length).to eq(4) end it 'writes the string' do expect(modified.write_position).to eq(4) end end context 'when bytes are not valid utf-8' do let(:string) do Utils.make_byte_string([254, 0, 255]).freeze end let(:modified) do buffer.put_bytes(string) end it 'writes the bytes' do expect(modified.to_s).to eq(string) end end end shared_examples_for 'bson string writer' do context 'given empty string' do let(:modified) do buffer.put_string('') end it 'writes length and null terminator' do expect(modified.write_position).to eq(5) end end context 'when string is not valid utf-8 in utf-8 encoding' do let(:string) do Utils.make_byte_string([254, 253, 255], 'utf-8') end before do expect(string.encoding.name).to eq('UTF-8') end it 'raises EncodingError' do # Precise exception classes and messages differ between MRI and JRuby expect do modified end.to raise_error(EncodingError) end end context 'when string is in binary encoding and cannot be encoded in utf-8' do let(:string) do Utils.make_byte_string([254, 253, 255], 'binary') end before do expect(string.encoding.name).to eq('ASCII-8BIT') end it 'raises Encoding::UndefinedConversionError' do expect do modified end.to raise_error(Encoding::UndefinedConversionError, /from ASCII-8BIT to UTF-8/) end end end describe '#put_string' do let(:modified) do buffer.put_string(string) end it_behaves_like 'bson string writer' context 'when the buffer does not need to be expanded' do context 'when the string is UTF-8' do let!(:modified) do buffer.put_string('testing') end it 'appends the string to the byte buffer' do expect(modified.to_s).to eq("#{8.to_bson.to_s}testing#{BSON::NULL_BYTE}") end it 'increments the write position by length + 5' do expect(modified.write_position).to eq(12) end end end context 'when the buffer needs to be expanded' do let(:string) do 300.times.inject(""){ |s, i| s << "#{i}" } end context 'when no bytes exist in the buffer' do let!(:modified) do buffer.put_string(string) end it 'appends the string to the byte buffer' do expect(modified.to_s).to eq("#{(string.bytesize + 1).to_bson.to_s}#{string}#{BSON::NULL_BYTE}") end it 'increments the write position by length + 5' do expect(modified.write_position).to eq(string.bytesize + 5) end end context 'when bytes exist in the buffer' do let!(:modified) do buffer.put_int32(4).put_string(string) end it 'appends the string to the byte buffer' do expect(modified.to_s).to eq( "#{[ 4 ].pack(BSON::Int32::PACK)}#{(string.bytesize + 1).to_bson.to_s}#{string}#{BSON::NULL_BYTE}" ) end it 'increments the write position by length + 5' do expect(modified.write_position).to eq(string.bytesize + 9) end end end context 'when string is in an encoding other than utf-8' do let(:string) do # "\xfe" Utils.make_byte_string([254], 'iso-8859-1') end let(:expected) do # \xc3\xbe == \u00fe Utils.make_byte_string([3, 0, 0, 0, 0xc3, 0xbe, 0]) end it 'is written as utf-8' do expect(modified.to_s).to eq(expected) end end end describe '#put_cstring' do let(:modified) do buffer.put_cstring(string) end it_behaves_like 'bson string writer' context 'when argument is a string' do context 'when the string is valid' do let!(:modified) do buffer.put_cstring('testing') end it 'appends the string plus null byte to the byte buffer' do expect(modified.to_s).to eq("testing#{BSON::NULL_BYTE}") end it 'increments the write position by the length + 1' do expect(modified.write_position).to eq(8) end it 'mutates receiver' do modified expect(buffer.write_position).to eq(8) end end context "when the string contains a null byte" do let(:string) do "test#{BSON::NULL_BYTE}ing" end it 'raises ArgumentError' do expect { modified }.to raise_error(ArgumentError, /String .* contains null bytes/) end end context 'when string is in an encoding other than utf-8' do let(:string) do # "\xfe" Utils.make_byte_string([254], 'iso-8859-1') end let(:expected) do # \xc3\xbe == \u00fe # No length prefix Utils.make_byte_string([0xc3, 0xbe, 0]) end it 'is written as utf-8' do expect(modified.to_s).to eq(expected) end end end context 'when argument is a symbol' do let(:modified) do buffer.put_cstring(:testing) end it 'writes' do expect(modified.to_s).to eq("testing#{BSON::NULL_BYTE}") end it 'increments the write position by the length + 1' do expect(modified.write_position).to eq(8) end it 'mutates receiver' do modified expect(buffer.write_position).to eq(8) end context 'when symbol includes a null byte' do let(:modified) do buffer.put_cstring(:"tes\x00ing") end it 'raises ArgumentError' do expect { modified }.to raise_error(ArgumentError, /String .* contains null bytes/) end it 'does not change write position' do begin buffer.put_cstring(:"tes\x00ing") rescue ArgumentError end expect(buffer.write_position).to eq(0) end end end context 'when argument is a Fixnum' do let(:modified) do buffer.put_cstring(1234) end it 'writes' do expect(modified.to_s).to eq("1234#{BSON::NULL_BYTE}") end it 'increments the write position by the length + 1' do expect(modified.write_position).to eq(5) end end context 'when argument is of an unsupported type' do let(:modified) do buffer.put_cstring(1234.0) end it 'raises TypeError' do expect do modified end.to raise_error(TypeError, /Invalid type for put_cstring/) end it 'does not change write position' do begin buffer.put_cstring(1234.0) rescue TypeError end expect(buffer.write_position).to eq(0) end end end describe '#put_symbol' do context 'normal symbol' do let(:modified) do buffer.put_symbol(:hello) end it 'writes the symbol as string' do expect(modified.to_s).to eq("\x06\x00\x00\x00hello\x00") end it 'advances write position' do # 4 byte length + 5 byte string + null byte expect(modified.write_position).to eq(10) end end context 'symbol with null byte' do let(:modified) do buffer.put_symbol(:"he\x00lo") end it 'writes the symbol as string' do expect(modified.to_s).to eq("\x06\x00\x00\x00he\x00lo\x00") end it 'advances write position' do # 4 byte length + 5 byte string + null byte expect(modified.write_position).to eq(10) end end context 'when symbol is not valid utf-8' do let(:symbol) do Utils.make_byte_string([254, 0, 255]).to_sym end let(:modified) do buffer.put_symbol(symbol) end it 'raises EncodingError' do # Precise exception classes and messages differ between MRI and JRuby expect do modified end.to raise_error(EncodingError) end end end describe '#put_double' do let(:modified) do buffer.put_double(1.2332) end it 'appends the double to the buffer' do expect(modified.to_s).to eq([ 1.2332 ].pack(Float::PACK)) end it 'increments the write position by 8' do expect(modified.write_position).to eq(8) end context 'when argument is an integer' do let(:modified) do buffer.put_double(3) end it 'writes a double' do expect(modified.to_s).to eq([ 3 ].pack(Float::PACK)) end it 'increments the write position by 8' do expect(modified.write_position).to eq(8) end end context 'when argument is a BigNum' do let(:value) { 123456789012345678901234567890 } let(:modified) do buffer.put_double(value) end let(:actual) do described_class.new(modified.to_s).get_double end it 'writes a double' do expect(actual).to be_within(1).of(value) end it 'increments the write position by 8' do expect(modified.write_position).to eq(8) end end context 'when argument is a string' do let(:modified) do buffer.put_double("hello") end it 'raises TypeError' do expect do modified end.to raise_error(TypeError, /no implicit conversion to float from string|ClassCastException:.*RubyString cannot be cast to.*RubyFloat/) expect(buffer.write_position).to eq(0) end end end describe '#put_int32' do context 'when the integer is 32 bit' do context 'when the integer is positive' do let!(:modified) do buffer.put_int32(Integer::MAX_32BIT - 1) end let(:expected) do [ Integer::MAX_32BIT - 1 ].pack(BSON::Int32::PACK) end it 'appends the int32 to the byte buffer' do expect(modified.to_s).to eq(expected) end it 'increments the write position by 4' do expect(modified.write_position).to eq(4) end end context 'when the integer is negative' do let!(:modified) do buffer.put_int32(Integer::MIN_32BIT + 1) end let(:expected) do [ Integer::MIN_32BIT + 1 ].pack(BSON::Int32::PACK) end it 'appends the int32 to the byte buffer' do expect(modified.to_s).to eq(expected) end it 'increments the write position by 4' do expect(modified.write_position).to eq(4) end end context 'when the integer is not 32 bit' do it 'raises an exception' do expect { buffer.put_int32(Integer::MAX_64BIT - 1) }.to raise_error(RangeError) end end end context 'when argument is a float' do let(:modified) do buffer.put_int32(4.934) end let(:expected) do [ 4 ].pack(BSON::Int32::PACK) end it 'appends the int32 to the byte buffer' do expect(modified.to_s).to eq(expected) end it 'increments the write position by 4' do expect(modified.write_position).to eq(4) end end end describe '#put_uint32' do context 'when argument is a float' do it 'raises an Argument Error' do expect{ buffer.put_uint32(4.934) }.to raise_error(ArgumentError, "put_uint32: incorrect type: float, expected: integer") end end context 'when number is in range' do let(:modified) do buffer.put_uint32(5) end it 'returns gets the correct number from the buffer' do expect(modified.get_uint32).to eq(5) end it 'returns the length of the buffer' do expect(modified.length).to eq(4) end end context 'when number is 0' do let(:modified) do buffer.put_uint32(0) end it 'returns gets the correct number from the buffer' do expect(modified.get_uint32).to eq(0) end it 'returns the length of the buffer' do expect(modified.length).to eq(4) end end context 'when number doesn\'t fit in signed int32' do let(:modified) do buffer.put_uint32(4294967295) end let(:expected) do [ 4294967295 ].pack(BSON::Int32::PACK) end it 'appends the int32 to the byte buffer' do expect(modified.to_s).to eq(expected) end it 'get returns correct number' do expect(modified.get_uint32).to eq(4294967295) end it 'returns the length of the buffer' do expect(modified.length).to eq(4) end end context 'when number is 2^31' do let(:modified) do buffer.put_uint32(2147483648) end it 'returns gets the correct number from the buffer' do expect(modified.get_uint32).to eq(2147483648) end it 'returns the length of the buffer' do expect(modified.length).to eq(4) end end context 'when number is 2^31-1' do let(:modified) do buffer.put_uint32(2147483647) end it 'returns gets the correct number from the buffer' do expect(modified.get_uint32).to eq(2147483647) end it 'returns the length of the buffer' do expect(modified.length).to eq(4) end end context 'when number is not in range' do it 'raises error on out of top range' do expect{ buffer.put_uint32(4294967296) }.to raise_error(RangeError, "Number 4294967296 is out of range [0, 2^32)") end it 'raises error on out of bottom range' do expect{ buffer.put_uint32(-1) }.to raise_error(RangeError, "Number -1 is out of range [0, 2^32)") end end end describe '#put_int64' do context 'when the integer is 64 bit' do context 'when the integer is positive' do let!(:modified) do buffer.put_int64(Integer::MAX_64BIT - 1) end let(:expected) do [ Integer::MAX_64BIT - 1 ].pack(BSON::Int64::PACK) end it 'appends the int64 to the byte buffer' do expect(modified.to_s).to eq(expected) end it 'increments the write position by 8' do expect(modified.write_position).to eq(8) end end context 'when the integer is negative' do let!(:modified) do buffer.put_int64(Integer::MIN_64BIT + 1) end let(:expected) do [ Integer::MIN_64BIT + 1 ].pack(BSON::Int64::PACK) end it 'appends the int64 to the byte buffer' do expect(modified.to_s).to eq(expected) end it 'increments the write position by 8' do expect(modified.write_position).to eq(8) end end context 'when the integer is larger than 64 bit' do it 'raises an exception' do expect { buffer.put_int64(Integer::MAX_64BIT + 1) }.to raise_error(RangeError) end end end context 'when integer fits in 32 bits' do let(:modified) do buffer.put_int64(1) end it 'increments the write position by 8' do expect(modified.write_position).to eq(8) end end context 'when argument is a float' do let(:modified) do buffer.put_int64(4.934) end let(:expected) do [ 4 ].pack(BSON::Int64::PACK) end it 'appends the int64 to the byte buffer' do expect(modified.to_s).to eq(expected) end it 'increments the write position by 8' do expect(modified.write_position).to eq(8) end end end describe '#replace_int32' do let(:exp_0) do [ 0 ].pack(BSON::Int32::PACK) end let(:exp_first) do [ 5 ].pack(BSON::Int32::PACK) end let(:exp_second) do [ 4 ].pack(BSON::Int32::PACK) end let(:exp_42) do [ 42 ].pack(BSON::Int32::PACK) end let(:modified) do buffer.replace_int32(0, 5) end context 'when there is sufficient data in buffer' do before do buffer.put_int32(0).put_int32(4) end it 'replaces the int32 at the location' do expect(modified.to_s).to eq("#{exp_first}#{exp_second}") end context 'when the position is negative' do let(:modified) do buffer.replace_int32(-1, 5) end it 'raises ArgumentError' do expect do modified end.to raise_error(ArgumentError, /Position.*cannot be negative/) end end context 'when the position is 4 bytes prior to write position' do let(:modified) do buffer.replace_int32(4, 42) end it 'replaces the int32 at the location' do expect(modified.to_s).to eq("#{exp_0}#{exp_42}") end end context 'when the position exceeds allowed range' do let(:modified) do # Buffer has 8 bytes but we can only write up to position 4 buffer.replace_int32(5, 42) end it 'raises ArgumentError' do expect do modified end.to raise_error(ArgumentError, /Position.*is out of bounds/) end end end context 'when there is insufficient data in buffer' do before do buffer.put_bytes("aa") end let(:modified) do buffer.replace_int32(1, 42) end it 'raises ArgumentError' do expect do modified end.to raise_error(ArgumentError, /Buffer does not have enough data/) end end end end bson-ruby-4.15.0/spec/bson/code_spec.rb000066400000000000000000000023361423026727100176750ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::Code do describe "#as_json" do let(:object) do described_class.new("this.value = 5") end it "returns the binary data plus type" do expect(object.as_json).to eq({ "$code" => "this.value = 5" }) end it_behaves_like "a JSON serializable object" end describe "#to_bson/#from_bson" do let(:type) { 13.chr } let(:obj) { described_class.new("this.value = 5") } let(:bson) { "#{15.to_bson}this.value = 5#{BSON::NULL_BYTE}" } it_behaves_like "a bson element" it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end end bson-ruby-4.15.0/spec/bson/code_with_scope_spec.rb000066400000000000000000000046351423026727100221250ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::CodeWithScope do describe "#==" do let(:object) do BSON::CodeWithScope.new("this.value = val", "test") end context "when the objects are equal" do let(:other) { described_class.new("this.value = val", "test") } it "returns true" do expect(object).to eq(other) end end context "when the other object is not equal" do let(:other) { described_class.new("this.value = otherVal", "test") } it "returns false" do expect(object).to_not eq(other) end end end describe "#as_json" do let(:object) do described_class.new("this.value = val", :val => "test") end it "returns the binary data plus type" do expect(object.as_json).to eq( { "$code" => "this.value = val", "$scope" => { :val => "test" }} ) end it_behaves_like "a JSON serializable object" end describe "#to_bson" do let(:type) { 15.chr } let(:code) { "this.value == name" } let(:scope) do { :name => "test" } end let(:obj) { described_class.new(code, scope) } let(:bson) do "#{47.to_bson.to_s}#{(code.length + 1).to_bson.to_s}#{code}#{BSON::NULL_BYTE}" + "#{scope.to_bson.to_s}" end it_behaves_like "a bson element" it_behaves_like "a serializable bson element" end describe "#from_bson" do let(:type) { 15.chr } let(:code) { "this.value == name" } let(:scope) do { "name" => "test" } end let(:obj) { described_class.new(code, scope) } let(:bson) { BSON::ByteBuffer.new(obj.to_bson.to_s) } let!(:deserialized) { described_class.from_bson(bson) } it "deserializes the javascript" do expect(deserialized.javascript).to eq(code) end it "deserializes the scope" do expect(deserialized.scope).to eq(scope) end end end bson-ruby-4.15.0/spec/bson/config_spec.rb000066400000000000000000000013531423026727100202260ustar00rootroot00000000000000require "spec_helper" describe BSON::Config do describe "#validating_keys?" do context "when the default is used" do it "returns false" do expect(described_class).to_not be_validating_keys end end context "when configuring to false" do before do BSON::Config.validating_keys = false end it "returns false" do expect(described_class).to_not be_validating_keys end end context "when configuring to true" do before do BSON::Config.validating_keys = true end after do BSON::Config.validating_keys = false end it "returns true" do expect(described_class).to be_validating_keys end end end end bson-ruby-4.15.0/spec/bson/date_spec.rb000066400000000000000000000023311423026727100176730ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe Date do it_behaves_like "a class which converts to Time" describe "#to_bson" do context "when the date is post epoch" do let(:obj) { Date.new(2012, 1, 1) } let(:time) { Time.utc(2012, 1, 1) } let(:bson) { [ (time.to_f * 1000).to_i ].pack(BSON::Int64::PACK) } it_behaves_like "a serializable bson element" end context "when the date is pre epoch" do let(:obj) { Date.new(1969, 1, 1) } let(:time) { Time.utc(1969, 1, 1) } let(:bson) { [ (time.to_f * 1000).to_i ].pack(BSON::Int64::PACK) } it_behaves_like "a serializable bson element" end end end bson-ruby-4.15.0/spec/bson/date_time_spec.rb000066400000000000000000000053041423026727100207140ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe DateTime do it_behaves_like "a class which converts to Time" describe "#to_bson" do context "when the date time is post epoch" do let(:obj) { DateTime.new(2012, 1, 1, 0, 0, 0) } let(:bson) { [ (obj.to_time.to_f * 1000).to_i ].pack(BSON::Int64::PACK) } it_behaves_like "a serializable bson element" end context "when the date time is pre epoch" do let(:obj) { DateTime.new(1969, 1, 1, 0, 0, 0) } let(:bson) { [ (obj.to_time.to_f * 1000).to_i ].pack(BSON::Int64::PACK) } it_behaves_like "a serializable bson element" end context "when the dates don't both use Gregorian" do let(:shakespeare_datetime) do DateTime.iso8601('1616-04-23', Date::ENGLAND) end let(:gregorian_datetime) do DateTime.iso8601('1616-04-23', Date::GREGORIAN) end context "when putting to bson" do let(:shakespeare) do { a: shakespeare_datetime }.to_bson end let(:gregorian) do { a: gregorian_datetime }.to_bson end it "does not equal each other" do expect(shakespeare.to_s).to_not eq(gregorian.to_s) end it "the english date is 10 days later" do expect(shakespeare.to_s).to eq({ a: DateTime.iso8601('1616-05-03', Date::GREGORIAN) }.to_bson.to_s) end end context "when putting and receiving from bson" do let(:shakespeare) do Hash.from_bson(BSON::ByteBuffer.new({ a: shakespeare_datetime }.to_bson.to_s)) end let(:gregorian) do Hash.from_bson(BSON::ByteBuffer.new({ a: gregorian_datetime }.to_bson.to_s)) end it "does not equal each other" do expect(shakespeare).to_not eq(gregorian) end it "the english date is 10 days later" do expect(shakespeare[:a]).to eq(DateTime.iso8601('1616-05-03', Date::GREGORIAN).to_time) end it "the gregorian date is the same" do expect(gregorian[:a]).to eq(DateTime.iso8601('1616-04-23', Date::GREGORIAN).to_time) end end end end end bson-ruby-4.15.0/spec/bson/dbref_legacy_spec.rb000066400000000000000000000071701423026727100213720ustar00rootroot00000000000000# frozen_string_literal: true # encoding: utf-8 require 'spec_helper' require 'json' # These tests are copied from driver when the driver implemented Mongo:DBRef # class, and are intended to verify that the current DBRef implementation is # compatible with the legacy driver DBRef interface. describe BSON::DBRef do let(:object_id) do BSON::ObjectId.new end describe '#as_json' do context 'when the database is not provided' do let(:dbref) do described_class.new('users', object_id) end it 'returns the json document without database' do expect(dbref.as_json).to eq({ '$ref' => 'users', '$id' => object_id }) end end context 'when the database is provided' do let(:dbref) do described_class.new('users', object_id, 'database') end it 'returns the json document with database' do expect(dbref.as_json).to eq({ '$ref' => 'users', '$id' => object_id, '$db' => 'database' }) end end end describe '#initialize' do let(:dbref) do described_class.new('users', object_id) end it 'sets the collection' do expect(dbref.collection).to eq('users') end it 'sets the id' do expect(dbref.id).to eq(object_id) end context 'when a database is provided' do let(:dbref) do described_class.new('users', object_id, 'db') end it 'sets the database' do expect(dbref.database).to eq('db') end context 'when id is not provided' do let(:dbref) do described_class.new('users', nil, 'db') end it 'raises ArgumentError' do lambda do dbref end.should raise_error(ArgumentError) end end end end describe '#to_bson' do let(:dbref) do described_class.new('users', object_id, 'database') end it 'converts the underlying document to bson' do expect(dbref.to_bson.to_s).to eq(dbref.as_json.to_bson.to_s) end end describe '#to_json' do context 'when the database is not provided' do let(:dbref) do described_class.new('users', object_id) end it 'returns the json document without database' do expect(dbref.to_json).to eq("{\"$ref\":\"users\",\"$id\":#{object_id.to_json}}") end end context 'when the database is provided' do let(:dbref) do described_class.new('users', object_id, 'database') end it 'returns the json document with database' do expect(dbref.to_json).to eq("{\"$ref\":\"users\",\"$id\":#{object_id.to_json},\"$db\":\"database\"}") end end end describe '#from_bson' do let(:buffer) do dbref.to_bson end let(:decoded) do BSON::Document.from_bson(BSON::ByteBuffer.new(buffer.to_s)) end context 'when a database exists' do let(:dbref) do described_class.new('users', object_id, 'database') end it 'decodes the ref' do expect(decoded.collection).to eq('users') end it 'decodes the id' do expect(decoded.id).to eq(object_id) end it 'decodes the database' do expect(decoded.database).to eq('database') end end context 'when no database exists' do let(:dbref) do described_class.new('users', object_id) end it 'decodes the ref' do expect(decoded.collection).to eq('users') end it 'decodes the id' do expect(decoded.id).to eq(object_id) end it 'sets the database to nil' do expect(decoded.database).to be_nil end end end end bson-ruby-4.15.0/spec/bson/dbref_spec.rb000066400000000000000000000277501423026727100200540ustar00rootroot00000000000000# frozen_string_literal: true # encoding: utf-8 require 'spec_helper' require 'json' describe BSON::DBRef do let(:object_id) do BSON::ObjectId.new end describe '#as_json' do context 'when the database is not provided' do let(:dbref) do described_class.new({ '$ref' => 'users', '$id' => object_id }) end it 'returns the json document without database' do expect(dbref.as_json).to eq({ '$ref' => 'users', '$id' => object_id }) end end context 'when the database is provided' do let(:dbref) do described_class.new({ '$ref' => 'users', '$id' => object_id, '$db' => 'database' }) end it 'returns the json document with database' do expect(dbref.as_json).to eq({ '$ref' => 'users', '$id' => object_id, '$db' => 'database' }) end end context 'when other keys are provided' do let(:dbref) do described_class.new({ '$ref' => 'users', '$id' => object_id, '$db' => 'database', 'x' => 'y' }) end it 'returns the json document with the other keys' do expect(dbref.as_json).to eq({ '$ref' => 'users', '$id' => object_id, '$db' => 'database', 'x' => 'y' }) end end end describe '#initialize' do let(:dbref) do described_class.new(hash) end let(:hash) do { '$ref' => 'users', '$id' => object_id } end it 'sets the collection' do expect(dbref.collection).to eq('users') end it 'sets the id' do expect(dbref.id).to eq(object_id) end context 'when first argument is a hash and two arguments are provided' do let(:dbref) do described_class.new({:$ref => 'users', :$id => object_id}, object_id) end it 'raises ArgumentError' do lambda do dbref end.should raise_error(ArgumentError) end end context 'when first argument is a hash and three arguments are provided' do let(:dbref) do described_class.new({:$ref => 'users', :$id => object_id}, object_id, 'db') end it 'raises ArgumentError' do lambda do dbref end.should raise_error(ArgumentError) end end context 'when a database is provided' do let(:hash) do { '$ref' => 'users', '$id' => object_id, '$db' => 'db' } end it 'sets the database' do expect(dbref.database).to eq('db') end end context 'when not providing a collection' do let(:hash) do { '$id' => object_id, '$db' => 'db' } end it 'raises an error' do expect do dbref end.to raise_error(ArgumentError, /DBRef must have \$ref/) end end context 'when not providing an id' do let(:hash) do { '$ref' => 'users', '$db' => 'db' } end it 'raises an error' do expect do dbref end.to raise_error(ArgumentError, /DBRef must have \$id/) end end context 'when providing an invalid type for ref' do let(:hash) do { '$ref' => 1, '$id' => object_id } end it 'raises an error' do expect do dbref end.to raise_error(ArgumentError, /The value for key \$ref must be a string/) end end context 'when providing an invalid type for database' do let(:hash) do { '$ref' => 'users', '$id' => object_id, '$db' => 1 } end it 'raises an error' do expect do dbref end.to raise_error(ArgumentError, /The value for key \$db must be a string/) end end context 'when providing the fieds as symbols' do let(:hash) do { :$ref => 'users', :$id => object_id, :$db => 'db' } end it 'does not raise an error' do expect do dbref end.to_not raise_error end end context 'when testing the ordering of the fields' do context 'when the fields are in order' do let(:hash) do { '$ref' => 'users', '$id' => object_id, '$db' => 'db' } end it 'has the correct order' do expect(dbref.keys).to eq(['$ref', '$id', '$db']) end end context 'when the fields are out of order' do let(:hash) do { '$db' => 'db', '$id' => object_id, '$ref' => 'users' } end it 'has the correct order' do expect(dbref.keys).to eq(['$ref', '$id', '$db']) end end context 'when there is no db' do let(:hash) do { '$id' => object_id, '$ref' => 'users' } end it 'has the correct order' do expect(dbref.keys).to eq(['$ref', '$id']) end end context 'when the there are other fields in order' do let(:hash) do { '$ref' => 'users', '$id' => object_id, '$db' => 'db', 'x' => 'y', 'y' => 'z' } end it 'has the correct order' do expect(dbref.keys).to eq(['$ref', '$id', '$db', 'x', 'y']) end end context 'when the there are other fields out of order' do let(:hash) do { 'y' => 'z', '$db' => 'db', '$id' => object_id, 'x' => 'y', '$ref' => 'users' } end it 'has the correct order' do expect(dbref.keys).to eq(['$ref', '$id', '$db', 'y', 'x']) end end end end describe '#to_bson' do let(:dbref) do described_class.new({ '$ref' => 'users', '$id' => object_id, '$db' => 'database' }) end it 'converts the underlying document to bson' do expect(dbref.to_bson.to_s).to eq(dbref.as_json.to_bson.to_s) end end describe '#to_json' do context 'when the database is not provided' do let(:dbref) do described_class.new({ '$ref' => 'users', '$id' => object_id }) end it 'returns the json document without database' do expect(dbref.to_json).to eq("{\"$ref\":\"users\",\"$id\":#{object_id.to_json}}") end end context 'when the database is provided' do let(:dbref) do described_class.new({ '$ref' => 'users', '$id' => object_id, '$db' => 'database' }) end it 'returns the json document with database' do expect(dbref.to_json).to eq("{\"$ref\":\"users\",\"$id\":#{object_id.to_json},\"$db\":\"database\"}") end end context 'when other keys are provided' do let(:dbref) do described_class.new({ '$ref' => 'users', '$id' => object_id, '$db' => 'database', 'x' => 'y' }) end it 'returns the json document with the other keys' do expect(dbref.to_json).to eq("{\"$ref\":\"users\",\"$id\":#{object_id.to_json},\"$db\":\"database\",\"x\":\"y\"}") end end end describe '#from_bson' do let(:buffer) do hash.to_bson end let(:decoded) do BSON::Document.from_bson(BSON::ByteBuffer.new(buffer.to_s)) end context 'when a database exists' do let(:hash) do { '$ref' => 'users', '$id' => object_id, '$db' => 'database' } end it 'decodes the ref' do expect(decoded.collection).to eq('users') end it 'decodes the id' do expect(decoded.id).to eq(object_id) end it 'decodes the database' do expect(decoded.database).to eq('database') end it 'is of class DBRef' do expect(decoded).to be_a described_class end end context 'when no database exists' do let(:hash) do { '$ref' => 'users', '$id' => object_id } end it 'decodes the ref' do expect(decoded.collection).to eq('users') end it 'decodes the id' do expect(decoded.id).to eq(object_id) end it 'sets the database to nil' do expect(decoded.database).to be_nil end it 'is of class DBRef' do expect(decoded).to be_a described_class end end context 'when other keys exist' do let(:hash) do { '$ref' => 'users', '$id' => object_id, 'x' => 'y' } end it 'decodes the key' do expect(decoded['x']).to eq('y') end it 'is of class DBRef' do expect(decoded).to be_a described_class end end context 'when it is an invalid dbref' do shared_examples 'bson document' do it 'should not raise' do expect do decoded end.to_not raise_error end it 'has the correct class' do expect(decoded).to be_a BSON::Document expect(decoded).to_not be_a described_class end end context 'when the hash has invalid collection type' do let(:hash) do { '$ref' => 1, '$id' => object_id } end include_examples 'bson document' end context 'when the hash has an invalid database type' do let(:hash) do { '$ref' => 'users', '$id' => object_id, '$db' => 1 } end include_examples 'bson document' end context 'when the hash is missing a collection' do let(:hash) do { '$id' => object_id } end include_examples 'bson document' end context 'when the hash is missing an id' do let(:hash) do { '$ref' => 'users' } end include_examples 'bson document' end end context 'when nesting the dbref' do context 'when it is a valid dbref' do let(:hash) do { 'dbref' => { '$ref' => 'users', '$id' => object_id } } end it 'should not raise' do expect do buffer end.to_not raise_error end it 'has the correct class' do expect(decoded['dbref']).to be_a described_class end end context 'when it is an invalid dbref' do shared_examples 'nested bson document' do it 'should not raise' do expect do decoded end.to_not raise_error end it 'has the correct class' do expect(decoded['dbref']).to be_a BSON::Document expect(decoded['dbref']).to_not be_a described_class end end context 'when the hash has invalid collection type' do let(:hash) do { 'dbref' => { '$ref' => 1, '$id' => object_id } } end include_examples 'nested bson document' end context 'when the hash has an invalid database type' do let(:hash) do { 'dbref' => { '$ref' => 'users', '$id' => object_id, '$db' => 1 } } end include_examples 'nested bson document' end context 'when the hash is missing a collection' do let(:hash) do { 'dbref' => { '$id' => object_id } } end include_examples 'nested bson document' end context 'when the hash is missing an id' do let(:hash) do { 'dbref' => { '$ref' => 'users' } } end include_examples 'nested bson document' end end end context 'when nesting a dbref inside a dbref' do context 'when it is a valid dbref' do let(:hash) do { 'dbref1' => { '$ref' => 'users', '$id' => object_id, 'dbref2' => { '$ref' => 'users', '$id' => object_id } } } end it 'should not raise' do expect do buffer end.to_not raise_error end it 'has the correct class' do expect(decoded['dbref1']).to be_a described_class expect(decoded['dbref1']['dbref2']).to be_a described_class end end context 'when it is an invalid dbref' do let(:hash) do { 'dbref' => { '$ref' => 'users', '$id' => object_id, 'dbref' => { '$ref' => 1, '$id' => object_id } } } end it 'should not raise' do expect do decoded end.to_not raise_error end it 'has the correct class' do expect(decoded['dbref']).to be_a described_class expect(decoded['dbref']['dbref']).to be_a BSON::Document end end end end end bson-ruby-4.15.0/spec/bson/decimal128_spec.rb000066400000000000000000001330671423026727100206220ustar00rootroot00000000000000# Copyright (C) 2016-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::Decimal128 do let(:low_bits) do decimal128.instance_variable_get(:@low) end let(:high_bits) do decimal128.instance_variable_get(:@high) end describe '#initialize' do context 'when the argument is neither a BigDecimal or String' do it 'raises an ArgumentError' do expect { described_class.new(:invalid) }.to raise_exception(ArgumentError) end end shared_examples_for 'an initialized BSON::Decimal128' do let(:decimal128) do described_class.new(argument) end let(:buffer) do decimal128.to_bson end let(:from_bson) do described_class.from_bson(buffer) end let(:expected_bson) do [expected_low_bits].pack(BSON::Int64::PACK) + [expected_high_bits].pack(BSON::Int64::PACK) end it 'sets the correct high order bits' do expect(high_bits).to eq(expected_high_bits) end it 'sets the correct low order bits' do expect(low_bits).to eq(expected_low_bits) end it 'serializes to bson' do expect(buffer.to_s).to eq(expected_bson) end it 'deserializes to the correct bits' do expect(from_bson.instance_variable_get(:@high)).to eq(expected_high_bits) expect(from_bson.instance_variable_get(:@low)).to eq(expected_low_bits) end end context 'when the object represents positive infinity' do let(:expected_high_bits) { 0x7800000000000000 } let(:expected_low_bits) { 0x0000000000000000 } context 'when a BigDecimal is passed' do let(:argument) { BigDecimal("Infinity") } it_behaves_like 'an initialized BSON::Decimal128' end context 'when a String is passed' do let(:argument) { "Infinity" } it_behaves_like 'an initialized BSON::Decimal128' end end context 'when the object represents negative infinity' do let(:expected_high_bits) { 0xf800000000000000 } let(:expected_low_bits) { 0x0000000000000000 } context 'when a BigDecimal is passed' do let(:argument) { BigDecimal("-Infinity") } it_behaves_like 'an initialized BSON::Decimal128' end context 'when a String is passed' do let(:argument) { "-Infinity" } it_behaves_like 'an initialized BSON::Decimal128' end end context 'when the object represents NaN' do let(:expected_high_bits) { 0x7c00000000000000 } let(:expected_low_bits) { 0x0000000000000000 } context 'when a BigDecimal is passed' do let(:argument) { BigDecimal("NaN") } it_behaves_like 'an initialized BSON::Decimal128' end context 'when a String is passed' do let(:argument) { "NaN" } it_behaves_like 'an initialized BSON::Decimal128' end end context 'when the object represents -NaN' do let(:expected_high_bits) { 0xfc00000000000000 } let(:expected_low_bits) { 0x0000000000000000 } context 'when a String is passed' do let(:argument) { "-NaN" } it_behaves_like 'an initialized BSON::Decimal128' end end context 'when the object represents SNaN' do let(:expected_high_bits) { 0x7e00000000000000 } let(:expected_low_bits) { 0x0000000000000000 } context 'when a String is passed' do let(:argument) { "SNaN" } it_behaves_like 'an initialized BSON::Decimal128' end end context 'when the object represents -SNaN' do let(:expected_high_bits) { 0xfe00000000000000 } let(:expected_low_bits) { 0x0000000000000000 } context 'when a String is passed' do let(:argument) { "-SNaN" } it_behaves_like 'an initialized BSON::Decimal128' end end context 'when the object represents -0' do let(:expected_high_bits) { 0xb040000000000000 } let(:expected_low_bits) { 0x0000000000000000 } context 'when a BigDecimal is passed' do let(:argument) { BigDecimal("-0") } it_behaves_like 'an initialized BSON::Decimal128' end context 'when a String is passed' do let(:argument) { "-0" } it_behaves_like 'an initialized BSON::Decimal128' end end context 'when the object represents a positive integer' do let(:expected_high_bits) { 0x3040000000000000 } let(:expected_low_bits) { 0x000000000000000c } context 'when a BigDecimal is passed' do let(:argument) { BigDecimal(12) } it_behaves_like 'an initialized BSON::Decimal128' end context 'when a String is passed' do let(:argument) { "12" } it_behaves_like 'an initialized BSON::Decimal128' end end context 'when the object represents a negative integer' do let(:expected_high_bits) { 0xb040000000000000 } let(:expected_low_bits) { 0x000000000000000c } context 'when a BigDecimal is passed' do let(:argument) { BigDecimal(-12) } it_behaves_like 'an initialized BSON::Decimal128' end context 'when a String is passed' do let(:argument) { "-12" } it_behaves_like 'an initialized BSON::Decimal128' end end context 'when the object represents a positive float' do let(:expected_high_bits) { 0x3036000000000000 } let(:expected_low_bits) { 0x0000000000003039 } context 'when a BigDecimal is passed' do let(:argument) { BigDecimal(0.12345, 5) } it_behaves_like 'an initialized BSON::Decimal128' end context 'when a String is passed' do let(:argument) { "0.12345" } it_behaves_like 'an initialized BSON::Decimal128' end end context 'when the object represents a negative float' do let(:expected_high_bits) { 0xb036000000000000 } let(:expected_low_bits) { 0x0000000000003039 } context 'when a BigDecimal is passed' do let(:argument) { BigDecimal(-0.12345, 5) } it_behaves_like 'an initialized BSON::Decimal128' end context 'when a String is passed' do let(:argument) { "-0.12345" } it_behaves_like 'an initialized BSON::Decimal128' end end context 'when the object represents a large positive integer' do let(:expected_high_bits) { 0x30403cde6fff9732 } let(:expected_low_bits) { 0xde825cd07e96aff2 } context 'when a BigDecimal is passed' do let(:argument) { BigDecimal(1234567890123456789012345678901234) } it_behaves_like 'an initialized BSON::Decimal128' end context 'when a String is passed' do let(:argument) { "1234567890123456789012345678901234" } it_behaves_like 'an initialized BSON::Decimal128' end end context 'when the object represents a large negative integer' do let(:expected_high_bits) { 0xb0403cde6fff9732 } let(:expected_low_bits) { 0xde825cd07e96aff2 } context 'when a BigDecimal is passed' do let(:argument) { BigDecimal(-1234567890123456789012345678901234) } it_behaves_like 'an initialized BSON::Decimal128' end context 'when a String is passed' do let(:argument) { "-1234567890123456789012345678901234" } it_behaves_like 'an initialized BSON::Decimal128' end end context 'when range is exceeded' do it 'raises InvalidRange' do lambda do described_class.new('1e10000') end.should raise_error(BSON::Decimal128::InvalidRange, /Value out of range/) end end context 'when precision is exceeded' do it 'raises UnrepresentablePrecision' do lambda do described_class.new('1.000000000000000000000000000000000000000000000000001') end.should raise_error(BSON::Decimal128::UnrepresentablePrecision, /The value contains too much precision/) end end end context 'when deserializing' do context 'When the value has trailing zeroes' do let(:hex) do '18000000136400D0070000000000000000000000003A3000' end let(:packed) do [ hex ].pack('H*') end let(:buffer) do BSON::ByteBuffer.new(packed) end let(:decimal128) do BSON::Document.from_bson(buffer)['d'] end let(:object_from_string) do BSON::Decimal128.from_string('2.000') end it 'has the correct high order' do expect(decimal128.instance_variable_get(:@high)).to eq(3475090062469758976) end it 'has the correct low order' do expect(decimal128.instance_variable_get(:@low)).to eq(2000) end it 'matches the object created from a string' do expect(object_from_string).to eq(decimal128) end end end describe '#from_string' do shared_examples_for 'a decimal128 initialized from a string' do let(:decimal128) do BSON::Decimal128.from_string(string) end let(:low_bits) do decimal128.instance_variable_get(:@low) end let(:high_bits) do decimal128.instance_variable_get(:@high) end it 'sets the correct high order bits' do expect(high_bits).to eq(expected_high_bits) end it 'sets the correct low order bits' do expect(low_bits).to eq(expected_low_bits) end end context 'when the string represents a special type' do context "when the string is 'NaN'" do let(:string) { 'NaN' } let(:expected_high_bits) { 0x7c00000000000000 } let(:expected_low_bits) { 0x0000000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-NaN'" do let(:string) { '-NaN' } let(:expected_high_bits) { 0xfc00000000000000 } let(:expected_low_bits) { 0x0000000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is 'SNaN'" do let(:string) { 'SNaN' } let(:expected_high_bits) { 0x7e00000000000000 } let(:expected_low_bits) { 0x0000000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-SNaN'" do let(:string) { '-SNaN' } let(:expected_high_bits) { 0xfe00000000000000 } let(:expected_low_bits) { 0x0000000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is 'Infinity'" do let(:string) { 'Infinity' } let(:expected_exponent) { nil } let(:expected_significand) { nil } let(:expected_high_bits) { 0x7800000000000000 } let(:expected_low_bits) { 0x0000000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-Infinity'" do let(:string) { '-Infinity' } let(:expected_exponent) { nil } let(:expected_significand) { nil } let(:expected_high_bits) { 0xf800000000000000 } let(:expected_low_bits) { 0x0000000000000000 } it_behaves_like 'a decimal128 initialized from a string' end end context 'when the string represents 0' do context "when the string is '0'" do let(:string) { '0' } let(:expected_exponent) { 0 } let(:expected_significand) { 0 } let(:expected_high_bits) { 0x3040000000000000 } let(:expected_low_bits) { 0 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-0'" do let(:string) { '-0' } let(:expected_exponent) { 0 } let(:expected_significand) { 0 } let(:expected_high_bits) { 0xb040000000000000 } let(:expected_low_bits) { 0 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '0.0'" do let(:string) { '0.0' } let(:expected_exponent) { -1 } let(:expected_significand) { 0 } let(:expected_high_bits) { 0x303e000000000000 } let(:expected_low_bits) { 0 } it_behaves_like 'a decimal128 initialized from a string' end end context 'when the string represents an integer' do context "when the string is '1'" do let(:string) { '1' } let(:expected_exponent) { 0 } let(:expected_significand) { 1 } let(:expected_high_bits) { 0x3040000000000000 } let(:expected_low_bits) { 0x1 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-1'" do let(:string) { '-1'} let(:expected_exponent) { 0 } let(:expected_significand) { 1 } let(:expected_high_bits) { 0xb040000000000000 } let(:expected_low_bits) { 0x1 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '20'" do let(:string) { '20' } let(:expected_exponent) { 0 } let(:expected_significand) { 20 } let(:expected_low_bits) { 0x14 } let(:expected_high_bits) { 0x3040000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-20'" do let(:string) { '-20' } let(:expected_exponent) { 0 } let(:expected_significand) { 20 } let(:expected_low_bits) { 0x14 } let(:expected_high_bits) { 0xb040000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '12345678901234567'" do let(:string) { '12345678901234567' } let(:expected_exponent) { 0 } let(:expected_significand) { 12345678901234567 } let(:expected_low_bits) { 0x002bdc545d6b4b87 } let(:expected_high_bits) { 0x3040000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-12345678901234567'" do let(:string) { '-12345678901234567' } let(:expected_exponent) { 0 } let(:expected_significand) { 12345678901234567 } let(:expected_low_bits) { 0x002bdc545d6b4b87 } let(:expected_high_bits) { 0xb040000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '12345689012345789012345'" do let(:string) { '12345689012345789012345' } let(:expected_exponent) { 0 } let(:expected_significand) { 12345689012345789012345 } let(:expected_low_bits) { 0x42da3a76f9e0d979 } let(:expected_high_bits) { 0x304000000000029d } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-12345689012345789012345'" do let(:string) { '-12345689012345789012345' } let(:expected_exponent) { 0 } let(:expected_significand) { 12345689012345789012345 } let(:expected_low_bits) { 0x42da3a76f9e0d979 } let(:expected_high_bits) { 0xb04000000000029d } it_behaves_like 'a decimal128 initialized from a string' end end context 'when the string represents a fraction' do context "when the string is '0.1'" do let(:string) { '0.1' } let(:expected_exponent) { -1 } let(:expected_significand) { 1 } let(:expected_low_bits) { 0x1 } let(:expected_high_bits) { 0x303e000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-0.1'" do let(:string) { '-0.1' } let(:expected_exponent) { -1 } let(:expected_significand) { 1 } let(:expected_low_bits) { 0x1 } let(:expected_high_bits) { 0xb03e000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '0.123'" do let(:string) { '0.123' } let(:expected_exponent) { -3 } let(:expected_significand) { 123 } let(:expected_low_bits) { 0x7b } let(:expected_high_bits) { 0x303a000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-0.123'" do let(:string) { '-0.123' } let(:expected_exponent) { -3 } let(:expected_significand) { 123 } let(:expected_low_bits) { 0x7b } let(:expected_high_bits) { 0xb03a000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '0.1234567890123456789012345678901234'" do let(:string) { '0.1234567890123456789012345678901234' } let(:expected_exponent) { -34 } let(:expected_significand) { 1234567890123456789012345678901234 } let(:expected_low_bits) { 0xde825cd07e96aff2 } let(:expected_high_bits) { 0x2ffc3cde6fff9732 } it_behaves_like 'a decimal128 initialized from a string' end end context 'when the string represents a fraction with a whole number' do context "when the string is '1.2'" do let(:string) { '1.2' } let(:expected_exponent) { -1 } let(:expected_significand) { 12 } let(:expected_low_bits) { 0xc } let(:expected_high_bits) { 0x303e000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-1.2'" do let(:string) { '-1.2' } let(:expected_exponent) { -1 } let(:expected_significand) { 12 } let(:expected_low_bits) { 0xc } let(:expected_high_bits) { 0xb03e000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '1.234'" do let(:string) { '1.234' } let(:expected_exponent) { -3 } let(:expected_significand) { 1234 } let(:expected_low_bits) { 0x4d2 } let(:expected_high_bits) { 0x303a000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-1.234'" do let(:string) { '-1.234' } let(:expected_exponent) { -3 } let(:expected_significand) { 1234 } let(:expected_low_bits) { 0x4d2 } let(:expected_high_bits) { 0xb03a000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '123456789.123456789'" do let(:string) { '123456789.123456789' } let(:expected_exponent) { -9 } let(:expected_significand) { 123456789123456789 } let(:expected_low_bits) { 0x1b69b4bacd05f15 } let(:expected_high_bits) { 0x302e000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-123456789.123456789'" do let(:string) { '-123456789.123456789' } let(:expected_exponent) { -9 } let(:expected_significand) { 123456789123456789 } let(:expected_low_bits) { 0x1b69b4bacd05f15 } let(:expected_high_bits) { 0xb02e000000000000 } it_behaves_like 'a decimal128 initialized from a string' end end context 'when the string represents a decimal with trailing zeros' do context "when the string is '1.000'" do let(:string) { '1.000' } let(:expected_exponent) { -3 } let(:expected_significand) { 1000 } let(:expected_low_bits) { 0x3e8 } let(:expected_high_bits) { 0x303a000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-1.000'" do let(:string) { '-1.000' } let(:expected_exponent) { -3 } let(:expected_significand) { 1000 } let(:expected_low_bits) { 0x3e8 } let(:expected_high_bits) { 0xb03a000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '100.000'" do let(:string) { '100.000' } let(:expected_exponent) { -3 } let(:expected_significand) { 100000 } let(:expected_low_bits) { 0x186a0 } let(:expected_high_bits) { 0x303a000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-100.000'" do let(:string) { '-100.000' } let(:expected_exponent) { -3 } let(:expected_significand) { 100000 } let(:expected_low_bits) { 0x186a0 } let(:expected_high_bits) { 0xb03a000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '1.234000000'" do let(:string) { '1.234000000' } let(:expected_exponent) { -9 } let(:expected_significand) { 1234000000 } let(:expected_low_bits) { 0x498d5880 } let(:expected_high_bits) { 0x302e000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-1.234000000'" do let(:string) { '-1.234000000' } let(:expected_exponent) { -9 } let(:expected_significand) { 1234000000 } let(:expected_low_bits) { 0x498d5880 } let(:expected_high_bits) { 0xb02e000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context 'when there are zeros following the decimal that are not trailing' do context "when the string is '0.001234'" do let(:string) { '0.001234' } let(:expected_exponent) { -6 } let(:expected_significand) { 1234 } let(:expected_low_bits) { 0x4d2 } let(:expected_high_bits) { 0x3034000000000000 } it_behaves_like 'a decimal128 initialized from a string' end end context 'when there are zeros following the decimal that are not trailing' do context "when the string is '0.00123400000'" do let(:string) { '0.00123400000' } let(:expected_exponent) { -11 } let(:expected_significand) { 123400000 } let(:expected_low_bits) { 0x75aef40 } let(:expected_high_bits) { 0x302a000000000000 } it_behaves_like 'a decimal128 initialized from a string' end end end context 'when the string uses scientific notation' do context 'when the exponent is positive' do context 'when the positive exponent is denoted with E' do context "when the string is '1.2E4'" do let(:string) { '1.2E4' } let(:expected_exponent) { 3 } let(:expected_significand) { 12 } let(:expected_low_bits) { 0xc } let(:expected_high_bits) { 0x3046000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-1.2E4'" do let(:string) { '-1.2E4' } let(:expected_exponent) { 3 } let(:expected_significand) { 12 } let(:expected_low_bits) { 0xc } let(:expected_high_bits) { 0xb046000000000000 } it_behaves_like 'a decimal128 initialized from a string' end end context 'when the positive exponent is denoted with E+' do context "when the string is '1.2E+4'" do let(:string) { '1.2E4' } let(:expected_exponent) { 3 } let(:expected_significand) { 12 } let(:expected_low_bits) { 0xc } let(:expected_high_bits) { 0x3046000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-1.2E+4'" do let(:string) { '-1.2E4' } let(:expected_exponent) { 3 } let(:expected_significand) { 12 } let(:expected_low_bits) { 0xc } let(:expected_high_bits) { 0xb046000000000000 } it_behaves_like 'a decimal128 initialized from a string' end end end context 'when the exponent is negative' do context "when the string is '1.2E-4'" do let(:string) { '1.2E-4' } let(:expected_exponent) { -5 } let(:expected_significand) { 12 } let(:expected_low_bits) { 0xc } let(:expected_high_bits) { 0x3036000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-1.2E-4'" do let(:string) { '-1.2E-4' } let(:expected_exponent) { -5 } let(:expected_significand) { 12 } let(:expected_low_bits) { 0xc } let(:expected_high_bits) { 0xb036000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context 'when there are trailing zeros' do context "when the string is '1.200E-4'" do let(:string) { '1.200E-4' } let(:expected_exponent) { -7 } let(:expected_significand) { 1200 } let(:expected_low_bits) { 0x4b0 } let(:expected_high_bits) { 0x3032000000000000 } it_behaves_like 'a decimal128 initialized from a string' end context "when the string is '-1.200E-4'" do let(:string) { '-1.200E-4' } let(:expected_exponent) { -7 } let(:expected_significand) { 1200 } let(:expected_low_bits) { 0x4b0 } let(:expected_high_bits) { 0xb032000000000000 } it_behaves_like 'a decimal128 initialized from a string' end end end end end describe '#to_s' do shared_examples_for 'a decimal128 printed to a string' do let(:buffer) do buffer = BSON::ByteBuffer.new buffer.put_decimal128(low_bits, high_bits) end let(:decimal) { BSON::Decimal128.from_bson(buffer) } it 'prints the correct string' do expect(decimal.to_s).to eq(expected_string) end end context 'when the bits represent a special type' do context 'when the decimal is NaN' do let(:expected_string) { 'NaN' } let(:high_bits) { 0x7c00000000000000 } let(:low_bits) { 0x0 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is negative NaN' do let(:expected_string) { 'NaN' } let(:high_bits) { 0xfc00000000000000 } let(:low_bits) { 0x0000000000000000 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is SNaN' do let(:expected_string) { 'NaN' } let(:high_bits) { 0x7e00000000000000 } let(:low_bits) { 0x0000000000000000 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is -SNaN' do let(:expected_string) { 'NaN' } let(:high_bits) { 0xfe00000000000000 } let(:low_bits) { 0x0000000000000000 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is NaN with a payload' do let(:expected_string) { 'NaN' } let(:high_bits) { 0x7e00000000000000 } let(:low_bits) { 0x0000000000000008 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is positive Infinity' do let(:expected_string) { 'Infinity' } let(:high_bits) { 0x7800000000000000 } let(:low_bits) { 0x0000000000000000 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is negative Infinity' do let(:expected_string) { '-Infinity' } let(:high_bits) { 0xf800000000000000 } let(:low_bits) { 0x0000000000000000 } it_behaves_like 'a decimal128 printed to a string' end end context 'when the string represents an integer' do context 'when the decimal is 1' do let(:expected_string) { '1' } let(:high_bits) { 0x3040000000000000 } let(:low_bits) { 0x0000000000000001 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is -1' do let(:expected_string) { '-1' } let(:high_bits) { 0xb040000000000000 } let(:low_bits) { 0x0000000000000001 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is 20' do let(:expected_string) { '20' } let(:high_bits) { 0x3040000000000000 } let(:low_bits) { 0x0000000000000014 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is -20' do let(:expected_string) { '-20' } let(:high_bits) { 0xb040000000000000 } let(:low_bits) { 0x0000000000000014 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is 12345678901234567' do let(:expected_string) { '12345678901234567' } let(:high_bits) { 0x3040000000000000 } let(:low_bits) { 0x002bdc545d6b4b87 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is -12345678901234567' do let(:expected_string) { '-12345678901234567' } let(:high_bits) { 0xb040000000000000 } let(:low_bits) { 0x002bdc545d6b4b87 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is 12345689012345789012345' do let(:expected_string) { '12345689012345789012345' } let(:high_bits) { 0x304000000000029d } let(:low_bits) { 0x42da3a76f9e0d979 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is -12345689012345789012345' do let(:expected_string) { '-12345689012345789012345' } let(:high_bits) { 0xb04000000000029d } let(:low_bits) { 0x42da3a76f9e0d979 } it_behaves_like 'a decimal128 printed to a string' end end context 'when the string represents a fraction' do context 'when the decimal is 0.1' do let(:expected_string) { '0.1' } let(:high_bits) { 0x303e000000000000 } let(:low_bits) { 0x0000000000000001 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is -0.1' do let(:expected_string) { '-0.1' } let(:high_bits) { 0xb03e000000000000 } let(:low_bits) { 0x0000000000000001 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is 0.123' do let(:expected_string) { '0.123' } let(:high_bits) { 0x303a000000000000 } let(:low_bits) { 0x000000000000007b } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal is -0.123' do let(:expected_string) { '-0.123' } let(:high_bits) { 0xb03a000000000000 } let(:low_bits) { 0x000000000000007b } it_behaves_like 'a decimal128 printed to a string' end end context 'when the decimal should have leading zeros' do let(:expected_string) { '0.001234' } let(:high_bits) { 0x3034000000000000 } let(:low_bits) { 0x00000000000004d2 } it_behaves_like 'a decimal128 printed to a string' end context 'when the decimal has trailing zeros' do let(:expected_string) { '2.000' } let(:high_bits) { 0x303a000000000000 } let(:low_bits) { 0x00000000000007d0 } it_behaves_like 'a decimal128 printed to a string' end end describe "#==" do context "when the high and low bits are identical" do let(:string) do '1.23' end let(:decimal128) do described_class.from_string(string) end let(:other_decimal) do described_class.from_string(string) end it "returns true" do expect(decimal128).to eq(other_decimal) end end context "when the high and low bits are different" do let(:string) do '1.23' end let(:decimal128) do described_class.from_string(string) end it "returns false" do expect(decimal128).to_not eq(described_class.new(BigDecimal('2.00'))) end end context "when other is not a decimal128" do it "returns false" do expect(described_class.from_string('1')).to_not eq(nil) end end end describe "#===" do let(:decimal128) do described_class.new(BigDecimal('1.23')) end context "when comparing with another decimal128" do context "when the high and low bits are equal" do let(:other) do described_class.from_string(decimal128.to_s) end it "returns true" do expect(decimal128 === other).to be true end end context "when the high and low bits are not equal" do let(:other) do described_class.new(BigDecimal('1000.003')) end it "returns false" do expect(decimal128 === other).to be false end end end context "when comparing to an decimal128 class" do it "returns false" do expect(decimal128 === BSON::Decimal128).to be false end end context "when comparing with a non string or decimal128" do it "returns false" do expect(decimal128 === "test").to be false end end context "when comparing with a non decimal128 class" do it "returns false" do expect(decimal128 === String).to be false end end end describe "#as_json" do let(:object) do described_class.new(BigDecimal('1.23')) end it "returns the decimal128 with $numberDecimal key" do expect(object.as_json).to eq({ "$numberDecimal" => object.to_s }) end it_behaves_like "a JSON serializable object" end describe "::BSON_TYPE" do it "returns 0x13" do expect(described_class::BSON_TYPE).to eq(19.chr) end end describe "#bson_type" do let(:code) do described_class.new(BigDecimal('1.23')) end it "returns 0x13" do expect(code.bson_type).to eq(described_class::BSON_TYPE) end end describe "#eql" do context "when high and low bits are identical" do let(:string) do '2.00' end let(:decimal128) do described_class.from_string(string) end let(:other_decimal) do described_class.from_string(string) end it "returns true" do expect(decimal128).to eql(other_decimal) end end context "when the high and low bit are different" do let(:string) do '2.00' end let(:decimal128) do described_class.from_string(string) end it "returns false" do expect(decimal128).to_not eql(described_class.new(BigDecimal('2'))) end end context "when other is not a Decimal128" do it "returns false" do expect(described_class.from_string('2')).to_not eql(nil) end end end describe "#hash" do let(:decimal128) do described_class.new(BigDecimal('-1234E+33')) end it "returns a hash of the high and low bits" do expect(decimal128.hash).to eq(BSON::Decimal128.from_bson(decimal128.to_bson).hash) end end describe "#inspect" do let(:decimal128) do described_class.new(BigDecimal('1.23')) end it "returns the inspection with the decimal128 to_s" do expect(decimal128.inspect).to eq("BSON::Decimal128('#{decimal128.to_s}')") end end describe "#to_big_decimal" do shared_examples_for 'a decimal128 convertible to a Ruby BigDecimal' do let(:decimal128) do described_class.new(big_decimal) end it 'properly converts the Decimal128 to a BigDecimal' do expect(decimal128.to_big_decimal).to eq(expected_big_decimal) end end context 'when the Decimal128 is a special type' do context 'when the value is Infinity' do let(:big_decimal) do BigDecimal('Infinity') end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end context 'when the value is -Infinity' do let(:big_decimal) do BigDecimal('-Infinity') end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end end context 'when the value represents an Integer' do context 'when the value is 1' do let(:big_decimal) do BigDecimal(1) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end context 'when the value is -1' do let(:big_decimal) do BigDecimal(-1) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end context 'when the value is 20' do let(:big_decimal) do BigDecimal(20) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end context 'when the value is -20' do let(:big_decimal) do BigDecimal(-20) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end context 'when the value is 12345678901234567' do let(:big_decimal) do BigDecimal(12345678901234567) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end context 'when the value is -12345678901234567' do let(:big_decimal) do BigDecimal(-12345678901234567) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end context 'when the value is 12345689012345789012345' do let(:big_decimal) do BigDecimal(12345689012345789012345) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end context 'when the value is -12345689012345789012345' do let(:big_decimal) do BigDecimal(-12345689012345789012345) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end end context 'when the value has a fraction' do context 'when the value is 0.1' do let(:big_decimal) do BigDecimal(0.1, 1) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end context 'when the value is -0.1' do let(:big_decimal) do BigDecimal(-0.1, 1) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end context 'when the value is 0.123' do let(:big_decimal) do BigDecimal(0.123, 3) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end context 'when the value is -0.123' do let(:big_decimal) do BigDecimal(-0.123, 3) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end end context 'when the value has leading zeros' do let(:big_decimal) do BigDecimal(0.001234, 4) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end context 'when the value has trailing zeros' do let(:big_decimal) do BigDecimal(2.000, 4) end let(:expected_big_decimal) do big_decimal end it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal' end end context "when the class is loaded" do let(:registered) do BSON::Registry.get(described_class::BSON_TYPE, 'field') end it "registers the type" do expect(registered).to eq(described_class) end end %w(== ===).each do |eq_op| let(:lhs) { described_class.new('1.2e12') } describe "##{eq_op}" do context 'when rhs is equal to lhs' do context 'when both are Decimal128 instances' do let(:rhs) { described_class.new('1.2e12') } it 'is true' do (lhs == rhs).should be true end end context 'when rhs is of a different type' do [ 1200000000000, 1200000000000.0, BigDecimal('1.2e12'), ].each do |rhs| context "when rhs is #{rhs.class}" do it 'is true' do pending 'RUBY-2952' (lhs == rhs).should be true end end end end end context 'when rhs is not equal to lhs' do context 'when both are Decimal128 instances' do let(:rhs) { described_class.new('1.21e12') } it 'is false' do (lhs == rhs).should be false end end context 'when rhs is of a different type' do [ 1200000000001, 1200000000001.0, BigDecimal('1.21e12'), ].each do |rhs| context "when rhs is #{rhs.class}" do it 'is false' do (lhs == rhs).should be false end end end end end end end describe "#<=>" do let(:lhs) { described_class.new('1.2e12') } context 'when lhs is less than rhs' do context 'when both are Decimal128 instances' do let(:rhs) { described_class.new('1.21e12') } it 'is -1' do (lhs <=> rhs).should be -1 end end context 'when rhs is of a different type' do [ 1200000000001, 1200000000001.0, BigDecimal('1.21e12'), ].each do |rhs| context "when rhs is #{rhs.class}" do it 'is -1' do (lhs <=> rhs).should be -1 end end end end end context 'when rhs is equal to lhs' do context 'when both are Decimal128 instances' do let(:rhs) { described_class.new('1.2e12') } it 'is 0' do (lhs <=> rhs).should be 0 end end context 'when rhs is of a different type' do [ 1200000000000, 1200000000000.0, BigDecimal('1.2e12'), ].each do |rhs| context "when rhs is #{rhs.class}" do it 'is 0' do (lhs <=> rhs).should be 0 end end end end end context 'when rhs is greater than lhs' do context 'when both are Decimal128 instances' do let(:rhs) { described_class.new('1.1e12') } it 'is 1' do (lhs <=> rhs).should be 1 end end context 'when rhs is of a different type' do [ 1100000000000, 1100000000000.0, BigDecimal('1.1e12'), ].each do |rhs| context "when rhs is #{rhs.class}" do it 'is 1' do (lhs <=> rhs).should be 1 end end end end end end describe "#<" do let(:lhs) { described_class.new('1.2e12') } context 'when lhs is less than rhs' do context 'when both are Decimal128 instances' do let(:rhs) { described_class.new('1.21e12') } it 'is true' do (lhs < rhs).should be true end end context 'when rhs is of a different type' do [ 1200000000001, 1200000000001.0, BigDecimal('1.21e12'), ].each do |rhs| context "when rhs is #{rhs.class}" do it 'is true' do (lhs < rhs).should be true end end end end end context 'when rhs is equal to lhs' do context 'when both are Decimal128 instances' do let(:rhs) { described_class.new('1.2e12') } it 'is false' do (lhs < rhs).should be false end end context 'when rhs is of a different type' do [ 1200000000000, 1200000000000.0, BigDecimal('1.2e12'), ].each do |rhs| context "when rhs is #{rhs.class}" do it 'is false' do (lhs < rhs).should be false end end end end end context 'when rhs is greater than lhs' do context 'when both are Decimal128 instances' do let(:rhs) { described_class.new('1.1e12') } it 'is false' do (lhs < rhs).should be false end end context 'when rhs is of a different type' do [ 1100000000000, 1100000000000.0, BigDecimal('1.1e12'), ].each do |rhs| context "when rhs is #{rhs.class}" do it 'is false' do (lhs < rhs).should be false end end end end end end end bson-ruby-4.15.0/spec/bson/document_as_spec.rb000066400000000000000000000024161423026727100212630ustar00rootroot00000000000000# Copyright (C) 2021 MongoDB Inc. # # 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. require "spec_helper" # BSON::Document ActiveSupport extensions describe BSON::Document do require_active_support describe '#symbolize_keys' do context 'string keys' do let(:doc) do described_class.new('foo' => 'bar') end it 'works correctly' do doc.symbolize_keys.should == {foo: 'bar'} end end end describe '#symbolize_keys!' do context 'string keys' do let(:doc) do described_class.new('foo' => 'bar') end it 'raises ArgumentError' do lambda do doc.symbolize_keys! end.should raise_error(ArgumentError, /symbolize_keys! is not supported on BSON::Document instances/) end end end end bson-ruby-4.15.0/spec/bson/document_spec.rb000066400000000000000000000574571423026727100206170ustar00rootroot00000000000000# encoding: utf-8 # Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::Document do let(:keys) { %w(blue green red pink orange) } let(:vals) { %w(000099 009900 aa0000 cc0066 cc6633) } let(:doc) { described_class.new } let(:hash) do {} end let(:enum_class) do Enumerator end before do keys.each_with_index do |key, index| hash[key] = vals[index] doc[key] = vals[index] end end describe "#keys" do it "retains the insertion order" do expect(doc.keys).to eq(keys) end end describe "#values" do it "retains the insertion order" do expect(doc.values).to eq(vals) end end describe "#fetch" do let(:document) do described_class["key", "value", "key2", "value"] end context "when provided string keys" do it "returns the value" do expect(document.fetch("key")).to eq("value") end end context "when provided symbol keys" do it "returns the value" do expect(document.fetch(:key)).to eq("value") end end context "when key does not exist" do it "raises KeyError" do expect do document.fetch(:non_existent_key) end.to raise_exception(KeyError) end context "and default value is provided" do it "returns default value" do expect(document.fetch(:non_existent_key, false)).to eq(false) end end context "and block is passed" do it "returns result of the block" do expect(document.fetch(:non_existent_key, &:to_s)) .to eq("non_existent_key") end end end context "when key exists" do context "and default value is provided" do it "returns the value" do expect(document.fetch(:key, "other")).to eq("value") end end context "and block is passed" do it "returns the value" do expect(document.fetch(:key, &:to_s)).to eq("value") end end end end describe "#[]" do let(:document) do described_class["key", "value", "key2", "value"] end context "when provided string keys" do it "returns the value" do expect(document["key"]).to eq("value") end end context "when provided symbol keys" do it "returns the value" do expect(document[:key]).to eq("value") end end context "when key does not exist" do it "returns nil" do expect(document[:non_existent_key]).to be nil end end end describe "#[]=" do let(:key) { "purple" } let(:val) { "5422a8" } before do doc[key] = val end it "updates the length" do expect(doc.length).to eq(keys.length + 1) end it "adds the key to the end" do expect(doc.keys.last).to eq(key) end it "adds the value to the end" do expect(doc.values.last).to eq(val) end it "sets the value" do expect(doc[key]).to eq(val) end context 'when value is a hash' do let(:val) do {'foo' => {'bar' => 'baz'}} end it 'converts value to indifferent access' do expect(doc[key][:foo][:bar]).to eq('baz') end end context 'when value is an array with hash element' do let(:val) do [42, {'foo' => {'bar' => 'baz'}}] end it 'converts hash element to indifferent access' do expect(doc[key][1][:foo][:bar]).to eq('baz') end end end if described_class.instance_methods.include?(:dig) describe "#dig" do let(:document) do described_class.new("key1" => { :key2 => "value" }) end context "when provided string keys" do it "returns the value" do expect(document.dig("key1", "key2")).to eq("value") end end context "when provided symbol keys" do it "returns the value" do expect(document.dig(:key1, :key2)).to eq("value") end end end end if described_class.instance_methods.include?(:slice) describe "#slice" do let(:document) do described_class.new("key1" => "value1", key2: "value2") end context "when provided string keys" do it "is a BSON Document" do expect(document.slice("key1")).to be_a(BSON::Document) end it "returns the partial document" do expect(document.slice("key1")).to contain_exactly(['key1', 'value1']) end end context "when provided symbol keys" do it "is a BSON Document" do expect(document.slice(:key1)).to be_a(BSON::Document) end it "returns the partial document" do expect(document.slice(:key1)).to contain_exactly(['key1', 'value1']) end end context "when provided keys that do not exist in the document" do it "returns only the keys that exist in the document" do expect(document.slice(:key1, :key3)).to contain_exactly(['key1', 'value1']) end end end end describe "#except" do let(:document) do described_class.new("key1" => "value1", key2: "value2") end context "when provided string keys" do it "returns the partial document" do expect(document.except("key1")).to contain_exactly(['key2', 'value2']) end end context "when provided symbol keys" do it "returns the partial document" do expect(document.except(:key1)).to contain_exactly(['key2', 'value2']) end end end describe "#delete" do shared_examples_for "a document with deletable pairs" do let!(:deleted) { doc.delete(key) } it "returns the deleted value" do expect(deleted).to eq(val) end it "removes the key from the list" do expect(doc.keys.length).to eq(keys.length) end it "matches the keys length to the document length" do expect(doc.length).to eq(doc.keys.length) end context "when removing a bad key" do it "returns nil" do expect(doc.delete(bad_key)).to be_nil end context "when a block is provided" do it "returns the result of the block" do expect(doc.delete(bad_key) { |k| "golden key" }).to eq("golden key") end end end end context "when keys are strings" do let(:key) { "white" } let(:val) { "ffffff" } let(:bad_key) { "black" } before do doc[key] = val end it_behaves_like "a document with deletable pairs" end context "when keys are symbols" do let(:key) { :white } let(:val) { "ffffff" } let(:bad_key) { :black } before do doc[key] = val end it_behaves_like "a document with deletable pairs" end end describe "#to_hash" do it "returns the document" do expect(doc.to_hash).to eq(doc) end end describe "#to_a" do it "returns the key/value pairs as an array" do expect(doc.to_a).to eq(keys.zip(vals)) end end [ :has_key?, :key?, :include?, :member? ].each do |method| describe "##{method}" do context "when the key exists" do it "returns true" do expect(doc.send(method, "blue")).to be true end end context "when the key does not exist" do it "returns false" do expect(doc.send(method, "indigo")).to be false end end context "when the key exists and is requested with a symbol" do it "returns true" do expect(doc.send(method, :blue)).to be true end end context "when the key does not exist and is requested with a symbol" do it "returns false" do expect(doc.send(method, :indigo)).to be false end end end end [ :has_value?, :value? ].each do |method| describe "##{method}" do let(:key) { :purple } let(:val) { :'5422a8' } before do doc[key] = val end context "when the value exists" do it "returns true" do expect(doc.send(method, "000099")).to be true end end context "when the value does not exist" do it "returns false" do expect(doc.send(method, "ABCABC")).to be false end end context "when the value exists and is requested with a symbol" do it "returns true" do expect(doc.send(method, :'5422a8')).to be true end end context "when the value does not exist and is requested with a symbol" do it "returns false" do expect(doc.send(method, :ABCABC)).to be false end end end end describe "#each_key" do let(:iter_keys) {[]} context "when passed a block" do let!(:enum) do doc.each_key{ |k| iter_keys << k } end it "returns the document" do expect(enum).to equal(doc) end it "iterates over each of the keys" do expect(iter_keys).to eq(keys) end end context "when not passed a block" do let!(:enum) do doc.each_key end it "returns an enumerator" do expect(enum).to be_a(enum_class) end end end describe "#each_value" do let(:iter_vals) {[]} context "when passed a block" do let!(:enum) do doc.each_value{ |v| iter_vals << v } end it "returns the document" do expect(enum).to equal(doc) end it "iterates over each of the vals" do expect(iter_vals).to eq(vals) end end context "when not passed a block" do let!(:enum) do doc.each_value end it "returns an enumerator" do expect(enum).to be_a(enum_class) end end end [ :each, :each_pair ].each do |method| describe "##{method}" do let(:iter_keys) {[]} let(:iter_vals) {[]} context "when passed a block" do let!(:enum) do doc.send(method) do |k, v| iter_keys << k iter_vals << v end end it "returns the document" do expect(enum).to equal(doc) end it "iterates over each of the keys" do expect(iter_keys).to eq(keys) end it "iterates over each of the vals" do expect(iter_vals).to eq(vals) end end context "when not passed a block" do let!(:enum) do doc.send(method) end it "returns an enumerator" do expect(enum).to be_a(enum_class) end end context "when the document has been serialized" do let(:deserialized) do if YAML.respond_to?(:unsafe_load) # In psych >= 4.0.0 `load` is basically an alias to `safe_load`, # which will fail here. YAML.unsafe_load(YAML.dump(doc)) else YAML.load(YAML.dump(doc)) end end let!(:enum) do deserialized.send(method) do |k, v| iter_keys << k iter_vals << v end end it "iterates over each of the keys" do expect(iter_keys).to eq(keys) end it "iterates over each of the vals" do expect(iter_vals).to eq(vals) end end end end describe "#each_with_index" do it "iterates over the document passing an index" do doc.each_with_index do |pair, index| expect(pair).to eq([ keys[index], vals[index] ]) end end end describe "#find_all" do it "iterates in the correct order" do expect(doc.find_all{ true }.map(&:first)).to eq(keys) end end describe "#select" do it "iterates in the correct order" do expect(doc.select{ true }.map(&:first)).to eq(keys) end end [ :delete_if, :reject! ].each do |method| describe "##{method}" do let(:copy) { doc.dup } before do copy.delete("pink") end let!(:deleted) do doc.send(method){ |k, _| k == "pink" } end it "deletes elements for which the block is true" do expect(deleted).to eq(copy) end it "deletes the matching keys from the document" do expect(doc.keys).to_not include("pink") end it "returns the same document" do expect(deleted).to equal(doc) end end end describe "#reject" do let(:copy) { doc.dup } before do copy.delete("pink") end let!(:deleted) do doc.reject{ |k, _| k == "pink" } end it "deletes elements for which the block is true" do expect(deleted).to eq(copy) end it "deletes the matching keys from the new document" do expect(deleted.keys).to_not include("pink") end it "returns a new document" do expect(deleted).to_not equal(doc) end end describe "#clear" do before do doc.clear end it "clears out the keys" do expect(doc.keys).to be_empty end end describe "#merge" do let(:other) { described_class.new } context "when passed no block" do before do other["purple"] = "800080" other["violet"] = "ee82ee" end let!(:merged) do doc.merge(other) end it "merges the keys" do expect(merged.keys).to eq(keys + [ "purple", "violet" ]) end it "adds to the length" do expect(merged.length).to eq(doc.length + other.length) end it "returns a new document" do expect(merged).to_not equal(doc) end end context "when passed a block" do before do other[:a] = 0 other[:b] = 0 end let(:merged) do other.merge(:b => 2, :c => 7) do |key, old_val, new_val| new_val + 1 end end it "executes the block on each merged element" do expect(merged[:a]).to eq(0) expect(merged[:b]).to eq(3) expect(merged[:c]).to eq(7) end end end describe "#merge!" do let(:other) { described_class.new } context "when passed no block" do before do other["purple"] = "800080" other["violet"] = "ee82ee" end let(:merged) do doc.merge!(other) end it "merges the keys" do expect(merged.keys).to eq(keys + [ "purple", "violet" ]) end it "adds to the length" do expect(merged.length).to eq(doc.length) end it "returns the same document" do expect(merged).to equal(doc) end end context "when passed a block" do before do other[:a] = 0 other[:b] = 0 end let!(:merged) do other.merge!(:b => 2, :c => 7) do |key, old_val, new_val| new_val + 1 end end it "executes the block on each merged element" do expect(other[:a]).to eq(0) expect(other[:b]).to eq(3) expect(other[:c]).to eq(7) end end context "and the documents have no common keys" do before { other[:a] = 1 } it "does not execute the block" do expect(other.merge(b: 1) { |key, old, new| old + new }).to eq( BSON::Document.new(a: 1, b: 1) ) end end end describe "#shift" do let(:pair) do doc.shift end it "returns the first pair in the document" do expect(pair).to eq([ keys.first, vals.first ]) end it "removes the pair from the document" do expect(doc.keys).to_not eq(pair.first) end end describe "#inspect" do it "includes the hash inspect" do expect(doc.inspect).to include(hash.inspect) end end describe "#initialize" do context "when providing symbol keys" do let(:document) do described_class.new(:test => 2, :testing => 4) end it "converts the symbols to strings" do expect(document).to eq({ "test" => 2, "testing" => 4 }) end end context "when providing duplicate symbol and string keys" do let(:document) do described_class.new(:test => 2, "test" => 4) end it "uses the last provided string key value" do expect(document[:test]).to eq(4) end end context "when providing a nested hash with symbol keys" do let(:document) do described_class.new(:test => { :test => 4 }) end it "converts the nested keys to strings" do expect(document).to eq({ "test" => { "test" => 4 }}) end end context "when providing a nested hash multiple levels deep with symbol keys" do let(:document) do described_class.new(:test => { :test => { :test => 4 }}) end it "converts the nested keys to strings" do expect(document).to eq({ "test" => { "test" => { "test" => 4 }}}) end end context "when providing an array of nested hashes" do let(:document) do described_class.new(:test => [{ :test => 4 }]) end it "converts the nested keys to strings" do expect(document).to eq({ "test" => [{ "test" => 4 }]}) end end end describe "#replace" do let(:other) do described_class[:black, "000000", :white, "000000"] end let!(:original) { doc.replace(other) } it "replaces the keys" do expect(doc.keys).to eq(other.keys) end it "returns the document" do expect(original).to eq(doc) end end describe "#update" do let(:updated) { described_class.new } before do updated.update(:name => "Bob") end it "updates the keys" do expect(updated.keys).to eq([ "name" ]) end it "updates the values" do expect(updated.values).to eq([ "Bob" ]) end it "returns the same document" do expect(updated.update(:name => "Bob")).to equal(updated) end end describe "#invert" do let(:expected) do described_class[vals.zip(keys)] end it "inverts the hash in inverse order" do expect(doc.invert).to eq(expected) end it "inverts the keys" do expect(vals.zip(keys)).to eq(doc.invert.to_a) end end describe "#from_bson" do context "when the document has embedded documents in an array" do let(:embedded_document) do BSON::Document.new(n: 1) end let(:embedded_documents) do [ embedded_document ] end let(:document) do BSON::Document.new(field: 'value', embedded: embedded_documents) end let(:serialized) do document.to_bson.to_s end let(:deserialized) do described_class.from_bson(BSON::ByteBuffer.new(serialized)) end it 'deserializes the documents' do expect(deserialized).to eq(document) end it 'deserializes embedded documents as document type' do expect(deserialized[:embedded].first).to be_a(BSON::Document) end end end describe "#to_bson/#from_bson" do let(:type) { 3.chr } it_behaves_like "a bson element" context "when the hash has symbol keys" do let(:obj) do described_class[:ismaster, 1].freeze end let(:bson) do "#{19.to_bson}#{BSON::Int32::BSON_TYPE}ismaster#{BSON::NULL_BYTE}" + "#{1.to_bson}#{BSON::NULL_BYTE}" end it "properly serializes the symbol" do expect(obj.to_bson.to_s).to eq(bson) end end context "when the hash contains an array of hashes" do let(:obj) do described_class["key",[{"a" => 1}, {"b" => 2}]] end let(:bson) do "#{45.to_bson}#{Array::BSON_TYPE}key#{BSON::NULL_BYTE}" + "#{35.to_bson}"+ "#{BSON::Document::BSON_TYPE}0#{BSON::NULL_BYTE}#{12.to_bson}#{BSON::Int32::BSON_TYPE}a#{BSON::NULL_BYTE}#{1.to_bson}#{BSON::NULL_BYTE}" + "#{BSON::Document::BSON_TYPE}1#{BSON::NULL_BYTE}#{12.to_bson}#{BSON::Int32::BSON_TYPE}b#{BSON::NULL_BYTE}#{2.to_bson}#{BSON::NULL_BYTE}" + "#{BSON::NULL_BYTE}" + "#{BSON::NULL_BYTE}" end it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context "when the hash is a single level" do let(:obj) do described_class["key","value"] end let(:bson) do "#{20.to_bson}#{String::BSON_TYPE}key#{BSON::NULL_BYTE}" + "#{6.to_bson}value#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}" end it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context "when the hash is embedded" do let(:obj) do described_class["field", BSON::Document["key", "value"]] end let(:bson) do "#{32.to_bson}#{Hash::BSON_TYPE}field#{BSON::NULL_BYTE}" + "#{20.to_bson}#{String::BSON_TYPE}key#{BSON::NULL_BYTE}" + "#{6.to_bson}value#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}" end it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" let(:raw) do BSON::ByteBuffer.new(bson) end it "returns an instance of a BSON::Document" do expect(described_class.from_bson(raw)).to be_a(BSON::Document) end end end context "when encoding and decoding" do context "when the keys are utf-8" do let(:document) do described_class["gültig", "type"] end it_behaves_like "a document able to handle utf-8" end context "when the values are utf-8" do let(:document) do described_class["type", "gültig"] end it_behaves_like "a document able to handle utf-8" end context "when both the keys and values are utf-8" do let(:document) do described_class["gültig", "gültig"] end it_behaves_like "a document able to handle utf-8" end context "when the regexps are utf-8" do let(:document) do described_class["type", /^gültig/] end let(:deserialized) do described_class.from_bson(BSON::ByteBuffer.new(document.to_bson.to_s)) end it "serializes and deserializes properly" do expect(deserialized['type'].compile).to eq(/^gültig/) end end context "when utf-8 string values are in an array" do let(:document) do described_class["type", ["gültig"]] end it_behaves_like "a document able to handle utf-8" end context "when utf-8 code values are present" do let(:document) do described_class["code", BSON::Code.new("// gültig")] end it_behaves_like "a document able to handle utf-8" end context "when utf-8 code with scope values are present" do let(:document) do described_class["code", BSON::CodeWithScope.new("// gültig", {})] end it_behaves_like "a document able to handle utf-8" end context "given a utf-8-encodable string in another encoding" do let(:string) { "gültig" } let(:document) do described_class["type", string.encode("iso-8859-1")] end it 'converts the values to utf-8' do expect( BSON::Document.from_bson(BSON::ByteBuffer.new(document.to_bson.to_s)) ).to eq({ "type" => string }) end end context "given a binary string with utf-8 values" do let(:string) { "europäisch".force_encoding('binary') } let(:document) do described_class["type", string] end it "raises encoding error" do expect do document.to_bson end.to raise_error(Encoding::UndefinedConversionError, /from ASCII-8BIT to UTF-8/) end end end end bson-ruby-4.15.0/spec/bson/ext_json_parse_spec.rb000066400000000000000000000176171423026727100220160ustar00rootroot00000000000000# Copyright (C) 2020 MongoDB Inc. # # 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. require "spec_helper" describe "BSON::ExtJSON.parse" do let(:parsed) { BSON::ExtJSON.parse_obj(input) } context 'when input is true' do let(:input) { true } it 'returns true' do parsed.should == true end end context 'when input is false' do let(:input) { false } it 'returns false' do parsed.should == false end end context 'when input is nil' do let(:input) { nil } it 'returns nil' do parsed.should be nil end end context 'when input is a string' do let(:input) { 'hello' } it 'returns the string' do parsed.should == 'hello' end end context 'when input is a BSON timestamp' do let(:input) { {'$timestamp' => {'t' => 12345, 'i' => 42}} } it 'returns a BSON::Timestamp instance' do parsed.should == BSON::Timestamp.new(12345, 42) end end context 'when input is an ISO time' do let(:input) { {'$date' => '1970-01-01T00:00:04Z'} } it 'returns a Time instance ' do parsed.should be_a(Time) end it 'returns a Time instance with correct value' do parsed.should == Time.at(4) end it 'returns a Time instance in UTC' do parsed.zone.should == 'UTC' end end context 'when input is a Unix timestamp' do let(:input) { {'$date' => {'$numberLong' => '4000'}} } it 'returns a Time instance ' do parsed.should be_a(Time) end it 'returns a Time instance with correct value' do parsed.should == Time.at(4) end it 'returns a Time instance in UTC' do parsed.zone.should == 'UTC' end end context 'when input is an int32' do let(:input) do {'$numberInt' => '42'} end let(:parsed) { BSON::ExtJSON.parse_obj(input, mode: mode) } context 'when :mode is nil' do let(:mode) { nil } it 'returns Integer instance' do parsed.should be_a(Integer) parsed.should == 42 end end context 'when :mode is :bson' do let(:mode) { :bson } it 'returns Integer instance' do parsed.should be_a(Integer) parsed.should == 42 end end end context 'when input is an int64' do let(:input) do {'$numberLong' => '42'} end let(:parsed) { BSON::ExtJSON.parse_obj(input, mode: mode) } context 'when :mode is nil' do let(:mode) { nil } it 'returns Integer instance' do parsed.should be_a(Integer) parsed.should == 42 end end context 'when :mode is :bson' do let(:mode) { :bson } it 'returns Int64 instance' do parsed.should be_a(BSON::Int64) parsed.value.should == 42 end end end context 'when input is a hash' do let(:input) do {} end let(:parsed) { BSON::ExtJSON.parse_obj(input, mode: mode) } let(:mode) { :bson } context 'when mode is invalid' do let(:mode) { :foo } it 'raises an exception' do lambda do parsed end.should raise_error(ArgumentError, /Invalid value for :mode option/) end end context 'when it contains a string key with a null byte' do let(:input) do { "key\x00" => 1 } end it 'raises an exception' do lambda do parsed end.should raise_error(BSON::Error::ExtJSONParseError, /Hash key cannot contain a null byte/) end end context 'when it contains a symbol key with a null byte' do let(:input) do { "key\x00".to_sym => 1 } end it 'raises an exception' do lambda do parsed end.should raise_error(BSON::Error::ExtJSONParseError, /Hash key cannot contain a null byte/) end end context 'when it contains an integer key' do let(:input) do { 0 => 1 } end it 'does not raises an exception' do lambda do parsed end.should_not raise_error end end end context 'when input is a binary' do let(:data) do Base64.decode64("//8=") end context 'in current format' do let(:input) do { "$binary" => { "base64"=>"//8=", "subType"=>"00" } } end context 'when :mode is nil' do let(:mode) { nil } it 'returns BSON::Binary instance' do parsed.should be_a(BSON::Binary) parsed.data.should == data end end context 'when mode is :bson' do let(:mode) { :bson } it 'returns BSON::Binary instance' do parsed.should be_a(BSON::Binary) parsed.data.should == data end end end context 'in legacy format' do let(:input) do { "$binary"=>"//8=", "$type"=>"00" } end context 'when :mode is nil' do let(:mode) { nil } it 'returns BSON::Binary instance' do parsed.should be_a(BSON::Binary) parsed.data.should == data end end context 'when mode is :bson' do let(:mode) { :bson } it 'returns BSON::Binary instance' do parsed.should be_a(BSON::Binary) parsed.data.should == data end end end end context 'when input is a regex' do let(:pattern) { 'abc' } let(:options) { 'im' } context 'in current format' do let(:input) do { "$regularExpression" => { "pattern" => pattern, "options" => options } } end context 'when :mode is nil' do let(:mode) { nil } it 'returns a BSON::Regexp::Raw instance' do parsed.should be_a(BSON::Regexp::Raw) parsed.pattern.should == pattern parsed.options.should == options end end context 'when :mode is :bson' do let(:mode) { :bson } it 'returns a BSON::Regexp::Raw instance' do parsed.should be_a(BSON::Regexp::Raw) parsed.pattern.should == pattern parsed.options.should == options end end end context 'in legacy format' do let(:input) do { "$regex" => pattern, "$options" => options } end context 'when :mode is nil' do let(:mode) { nil } it 'returns a BSON::Regexp::Raw instance' do parsed.should be_a(BSON::Regexp::Raw) parsed.pattern.should == pattern parsed.options.should == options end end context 'when :mode is :bson' do let(:mode) { :bson } it 'returns a BSON::Regexp::Raw instance' do parsed.should be_a(BSON::Regexp::Raw) parsed.pattern.should == pattern parsed.options.should == options end end end context 'when $regularExpression is nested in $regex' do context 'with options' do let(:input) do { "$regex" => { "$regularExpression" => { "pattern" => "foo*", "options" => "" }, }, "$options" => "ix", } end it 'parses' do parsed.should == { '$regex' => BSON::Regexp::Raw.new('foo*'), '$options' => 'ix' } end end context 'without options' do let(:input) do { "$regex" => { "$regularExpression" => { "pattern" => "foo*", "options" => "" }, }, } end it 'parses' do parsed.should == { '$regex' => BSON::Regexp::Raw.new('foo*'), } end end end end end bson-ruby-4.15.0/spec/bson/false_class_spec.rb000066400000000000000000000014761423026727100212460ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe FalseClass do describe "#to_bson" do let(:obj) { false } let(:bson) { 0.chr } let(:type) { 8.chr } it_behaves_like "a bson element" it_behaves_like "a serializable bson element" end end bson-ruby-4.15.0/spec/bson/float_spec.rb000066400000000000000000000032501423026727100200640ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe Float do describe "#to_bson/#from_bson" do let(:type) { 1.chr } let(:obj) { 1.2332 } let(:bson) { [ obj ].pack(Float::PACK) } it_behaves_like "a bson element" it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end describe '#to_json' do it 'returns float' do 42.0.to_json.should == '42.0' end end describe '#as_extended_json' do context 'canonical mode' do it 'returns $numberDouble' do 42.0.as_extended_json.should == {'$numberDouble' => '42.0'} end end context 'relaxed mode' do let(:serialized) do 42.0.as_extended_json(mode: :relaxed) end it 'returns float' do serialized.should be_a(Float) serialized.should be_within(0.00001).of(42) end end context 'legacy mode' do let(:serialized) do 42.0.as_extended_json(mode: :legacy) end it 'returns float' do serialized.should be_a(Float) serialized.should be_within(0.00001).of(42) end end end end bson-ruby-4.15.0/spec/bson/hash_as_spec.rb000066400000000000000000000025761423026727100203770ustar00rootroot00000000000000# Copyright (C) 2021 MongoDB Inc. # # 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. require "spec_helper" describe 'Hash ActiveSupport extensions' do require_active_support describe '#symbolize_keys' do let(:symbolized) { hash.symbolize_keys } shared_examples 'works correctly' do it 'returns a hash' do symbolized.class.should be Hash end it 'works correctly' do hash.symbolize_keys.should == {foo: 'bar'} end end context 'string keys' do let(:hash) do {'foo' => 'bar'} end include_examples 'works correctly' end context 'symbol keys' do let(:hash) do {foo: 'bar'} end include_examples 'works correctly' end context 'both string and symbol keys' do let(:hash) do {'foo' => 42, foo: 'bar'} end include_examples 'works correctly' end end end bson-ruby-4.15.0/spec/bson/hash_spec.rb000066400000000000000000000242351423026727100177100ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe Hash do describe "#to_bson/#from_bson" do let(:type) { 3.chr } it_behaves_like "a bson element" context "when the hash is a single level" do let(:obj) do { "key" => "value" } end let(:bson) do "#{20.to_bson.to_s}#{String::BSON_TYPE}key#{BSON::NULL_BYTE}" + "#{6.to_bson.to_s}value#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}" end it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context "when the hash has non-string keys" do let(:obj) do { 1 => "value" } end let(:expected) do { "1" => "value" } end it "properly converts to bson" do expect(BSON::Document.from_bson(BSON::ByteBuffer.new(obj.to_bson.to_s))).to eq(expected) end end context "when the hash has invalid keys" do let(:obj) do { "$testing" => "value" } end context "when validating keys" do context "when validating globally" do before do BSON::Config.validating_keys = true end after do BSON::Config.validating_keys = false end it "raises an error" do expect { obj.to_bson }.to raise_error(BSON::String::IllegalKey) end context "when the hash contains an array of documents containing invalid keys" do let(:obj) do { "array" => [{ "$testing" => "value" }] } end it "raises an error" do expect { obj.to_bson }.to raise_error(BSON::String::IllegalKey) end end end context "when validating locally" do it "raises an error" do expect { obj.to_bson(BSON::ByteBuffer.new, true) }.to raise_error(BSON::String::IllegalKey) end context "when the hash contains an array of documents containing invalid keys" do let(:obj) do { "array" => [{ "$testing" => "value" }] } end it "raises an error" do expect { obj.to_bson(BSON::ByteBuffer.new, true) }.to raise_error(BSON::String::IllegalKey) end end end end context "when not validating keys" do let(:bson) do "#{25.to_bson.to_s}#{String::BSON_TYPE}$testing#{BSON::NULL_BYTE}" + "#{6.to_bson.to_s}value#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}" end it "serializes the hash" do expect(obj.to_bson.to_s).to eq(bson) end context "when the hash contains an array of documents containing invalid keys" do let(:obj) do { "array" => [{ "$testing" => "value" }] } end let(:bson) do "#{45.to_bson.to_s}#{Array::BSON_TYPE}array#{BSON::NULL_BYTE}" + "#{[{ "$testing" => "value" }].to_bson.to_s}#{BSON::NULL_BYTE}" end it "serializes the hash" do expect(obj.to_bson.to_s).to eq(bson) end end end end context "when the hash is embedded" do let(:obj) do { "field" => { "key" => "value" }} end let(:bson) do "#{32.to_bson.to_s}#{Hash::BSON_TYPE}field#{BSON::NULL_BYTE}" + "#{20.to_bson.to_s}#{String::BSON_TYPE}key#{BSON::NULL_BYTE}" + "#{6.to_bson.to_s}value#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}" end it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context 'with symbol values' do let(:value) { :foo } let(:serialized) do {foo: value}.to_bson.to_s end def perform_test(bson_type_to_use) Symbol.class_eval do alias_method :bson_type_orig, :bson_type define_method(:bson_type) do bson_type_to_use end end begin yield ensure Symbol.class_eval do alias_method :bson_type, :bson_type_orig remove_method :bson_type_orig end end end let(:bson_with_symbol) do "\x12\x00\x00\x00\x0Efoo\x00\x04\x00\x00\x00bar\x00\x00".force_encoding('binary') end let(:deserialized) do Hash.from_bson(BSON::ByteBuffer.new(bson_with_symbol)) end context 'when Symbol#bson_type is set to symbol' do let(:bson_type_to_use) { BSON::Symbol::BSON_TYPE } let(:expected) do "\x12\x00\x00\x00\x0Efoo\x00\x04\x00\x00\x00foo\x00\x00".force_encoding('binary') end it 'serializes to BSON symbol' do perform_test(bson_type_to_use) do serialized end.should == expected end it 'deserializes to Symbol' do deserialized.should == {'foo' => :bar} end end context 'when Symbol#bson_type is set to string' do let(:bson_type_to_use) { BSON::String::BSON_TYPE } let(:expected) do "\x12\x00\x00\x00\x02foo\x00\x04\x00\x00\x00foo\x00\x00".force_encoding('binary') end it 'serializes to BSON string' do perform_test(bson_type_to_use) do serialized end.should == expected end it 'deserializes to Symbol' do deserialized.should == {'foo' => :bar} end end end context 'when hash contains value of an unserializable class' do class HashSpecUnserializableClass end let(:obj) do {foo: HashSpecUnserializableClass.new} end it 'raises UnserializableClass' do lambda do obj.to_bson end.should raise_error(BSON::Error::UnserializableClass, # C extension does not provide hash key in the exception message. /(Hash value for key 'foo'|Value) does not define its BSON serialized type:.*HashSpecUnserializableClass/) end end context 'when reading from a byte buffer that was previously written to' do let(:buffer) do {foo: 42}.to_bson end it 'returns the original hash' do expect(Hash.from_bson(buffer)).to eq('foo' => 42) end end context 'when round-tripping a BigDecimal' do let(:to_bson) do {"x" => BigDecimal('1')}.to_bson end let(:from_bson) do Hash.from_bson(to_bson) end it 'doesn\'t raise on serialization' do expect do to_bson end.to_not raise_error end it 'deserializes as a BSON::Decimal128' do expect(from_bson).to eq({"x" => BSON::Decimal128.new('1')}) end end end describe '#to_bson' do context 'when a key is not valid utf-8' do let(:key) { Utils.make_byte_string([254, 253, 255]) } let(:hash) do {key => 'foo'} end let(:expected_message) do if BSON::Environment.jruby? # Uses JRE conversion to another encoding /Error serializing key.*Encoding::UndefinedConversionError/ else # Uses our validator /Key.*is not valid UTF-8/ end end it 'raises EncodingError' do expect do hash.to_bson end.to raise_error(EncodingError, expected_message) end end context 'when a key contains null bytes' do let(:hash) do {"\x00".force_encoding('BINARY') => 'foo'} end it 'raises ArgumentError' do expect do hash.to_bson end.to raise_error(ArgumentError, /[Kk]ey.*contains null bytes/) end end context 'when a value is not valid utf-8' do let(:hash) do {'foo' => [254, 253, 255].map(&:chr).join.force_encoding('BINARY')} end let(:expected_message) do /from ASCII-8BIT to UTF-8/ end it 'raises EncodingError' do expect do hash.to_bson end.to raise_error(EncodingError, expected_message) end end context 'when a value contains null bytes' do let(:hash) do {'foo' => "\x00".force_encoding('BINARY')} end it 'works' do expect do hash.to_bson end.not_to raise_error end end context 'when serializing a hash with a BigDecimal' do let(:hash) do {'foo' => BigDecimal('1')} end it 'works' do expect do hash.to_bson end.not_to raise_error end end end describe '#from_bson' do context 'when bson document has duplicate keys' do let(:buf) do buf = BSON::ByteBuffer.new buf.put_int32(37) buf.put_byte("\x02") buf.put_cstring('foo') buf.put_string('bar') buf.put_byte("\x02") buf.put_cstring('foo') buf.put_string('overwrite') buf.put_byte("\x00") BSON::ByteBuffer.new(buf.to_s) end let(:doc) { Hash.from_bson(buf) } it 'overwrites first value with second value' do doc.should == {'foo' => 'overwrite'} end end context 'when bson document has string and symbol keys of the same name' do let(:buf) do buf = BSON::ByteBuffer.new buf.put_int32(31) buf.put_byte("\x02") buf.put_cstring('foo') buf.put_string('bar') buf.put_byte("\x0e") buf.put_cstring('foo') buf.put_string('bar') buf.put_byte("\x00") BSON::ByteBuffer.new(buf.to_s) end let(:doc) { Hash.from_bson(buf) } it 'overwrites first value with second value' do doc.should == {'foo' => :bar} end end end end bson-ruby-4.15.0/spec/bson/int32_spec.rb000066400000000000000000000140541423026727100177220ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::Int32 do describe "#intiialize" do let(:obj) { described_class.new(integer) } context "when the integer is 32-bit" do let(:integer) { Integer::MAX_32BIT } it "wraps the integer" do expect(obj.value).to be(integer) end end context "when the integer is too large" do let(:integer) { Integer::MAX_32BIT + 1 } it "raises an out of range error" do expect do obj end.to raise_error(RangeError, /#{integer} cannot be stored in 32 bits/) end end context "when the integer is too small" do let(:integer) { Integer::MIN_32BIT - 1 } it "raises an out of range error" do expect { obj }.to raise_error(RangeError) end end context 'when argument is an Int32' do let(:integer) do described_class.new(described_class.new(50)) end it 'works' do expect(integer.value).to be 50 end end end describe "#from_bson" do let(:type) { 16.chr } let(:obj) { 123 } let(:bson) { [ obj ].pack(BSON::Int32::PACK) } it_behaves_like "a bson element" it_behaves_like "a deserializable bson element" end describe "when the integer is negative" do let(:decoded) { -1 } let(:encoded) { BSON::ByteBuffer.new([ -1 ].pack(BSON::Int32::PACK)) } let(:decoded_2) { -50 } let(:encoded_2) { BSON::ByteBuffer.new([ -50 ].pack(BSON::Int32::PACK)) } it "decodes a -1 correctly" do expect(BSON::Int32.from_bson(encoded)).to eq(decoded) end it "decodes a -50 correctly" do expect(BSON::Int32.from_bson(encoded_2)).to eq(decoded_2) end end describe "#to_bson" do context "when the integer is 32 bit" do let(:type) { 16.chr } let(:obj) { BSON::Int32.new(Integer::MAX_32BIT - 1) } let(:bson) { [ Integer::MAX_32BIT - 1 ].pack(BSON::Int32::PACK) } it_behaves_like "a serializable bson element" end end describe "#to_bson_key" do let(:obj) { BSON::Int32.new(Integer::MAX_32BIT - 1) } let(:encoded) { (Integer::MAX_32BIT - 1) } it "returns the key as an integer" do expect(obj.to_bson_key).to eq(encoded) end end describe "#==" do let(:object) do described_class.new(1) end context "when data is identical" do let(:other_object) do described_class.new(1) end it "returns true" do expect(object).to eq(other_object) end context "other object is of another integer type" do let(:other_object) do BSON::Int64.new(1) end it "returns false" do expect(object).not_to eq(other_object) end end end context "when the data is different" do let(:other_object) do described_class.new(2) end it "returns false" do expect(object).not_to eq(other_object) end end context "when other is not a BSON integer" do it "returns false" do expect(described_class.new(1)).to_not eq('1') end end end describe "#===" do let(:object) do described_class.new(1) end context "when comparing with another BSON int32" do context "when the data is equal" do let(:other_object) do described_class.new(1) end it "returns true" do expect(object === other_object).to be true end context "other object is of another integer type" do let(:other_object) do BSON::Int64.new(1) end it "returns false" do expect(object === other_object).to be false end end end context "when the data is not equal" do let(:other_object) do described_class.new(2) end it "returns false" do expect(object === other_object).to be false end end end context "when comparing to an object id class" do it "returns false" do expect(described_class.new(1) === described_class).to be false end end context "when comparing with a string" do context "when the data is equal" do let(:other) do '1' end it "returns false" do expect(object === other).to be false end end context "when the data is not equal" do let(:other) do '2' end it "returns false" do expect(object === other).to be false end end end context "when comparing with a non-bson integer object" do it "returns false" do expect(object === []).to be false end end context "when comparing with a non int64 class" do it "returns false" do expect(object === String).to be false end end end describe '#value' do let(:obj) { described_class.new(12345) } it 'returns value passed to initializer' do expect(obj.value).to eq(12345) end end describe '#as_extended_json' do context 'canonical mode' do it 'returns $numberInt' do described_class.new(42).as_extended_json.should == {'$numberInt' => '42'} end end context 'relaxed mode' do it 'returns integer' do described_class.new(42).as_extended_json(mode: :relaxed).should == 42 end end context 'legacy mode' do it 'returns integer' do described_class.new(42).as_extended_json(mode: :legacy).should be 42 end end end end bson-ruby-4.15.0/spec/bson/int64_spec.rb000066400000000000000000000162301423026727100177250ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::Int64 do describe "#intiialize" do let(:obj) { described_class.new(integer) } context "when the integer is 64-bit" do let(:integer) { Integer::MAX_64BIT - 1 } it "wraps the integer" do expect(obj.value).to be(integer) end end context "when the integer is too large" do let(:integer) { Integer::MAX_64BIT + 1 } it "raises an out of range error" do expect do obj end.to raise_error(RangeError, /#{integer} cannot be stored in 64 bits/) end end context "when the integer is too small" do let(:integer) { Integer::MIN_64BIT - 1 } it "raises an out of range error" do expect { obj }.to raise_error(RangeError) end end context 'when argument is an Int64' do let(:integer) do described_class.new(described_class.new(50)) end it 'works' do expect(integer.value).to be 50 end end end describe "#from_bson" do let(:type) { 18.chr } let(:obj) { 1325376000000 } let(:bson) { [ obj ].pack(BSON::Int64::PACK) } it_behaves_like "a bson element" it_behaves_like "a deserializable bson element" context 'canonical deserialization' do let(:integer) { 42 } let(:bson) do BSON::ByteBuffer.new(BSON::Int64.new(integer).to_bson.to_s) end let(:deserialized) do described_class.from_bson(bson, mode: :bson) end it 'deserializes to BSON::Int64' do deserialized.class.should be BSON::Int64 end it 'has the correct value' do deserialized.value.should == 42 end end context "when the integer is within the MRI Fixnum range" do let(:integer) { 2**30 - 1 } let(:bson) do BSON::ByteBuffer.new(BSON::Int64.new(integer).to_bson.to_s) end context "when on JRuby", if: BSON::Environment.jruby? do it "deserializes to a Fixnum object" do expect(described_class.from_bson(bson).class).to be(Fixnum) end end it "deserializes to an Integer object" do expect(described_class.from_bson(bson).class).to be(Integer) end end context "when the 64-bit integer is the BSON max and thus larger than the MRI Fixnum range on all architectures" do let(:integer) { Integer::MAX_64BIT } let(:bson) do BSON::ByteBuffer.new(integer.to_bson.to_s) end context "when on JRuby", if: BSON::Environment.jruby? do it "deserializes to a Fixnum object" do expect(described_class.from_bson(bson).class).to be(Fixnum) end end it "deserializes to an Integer object" do expect(described_class.from_bson(bson).class).to be(Integer) end end end describe "#to_bson" do context "when the integer is 64 bit" do let(:type) { 18.chr } let(:obj) { BSON::Int64.new(Integer::MAX_64BIT - 1) } let(:bson) { [ Integer::MAX_64BIT - 1 ].pack(BSON::Int64::PACK) } it_behaves_like "a serializable bson element" end end describe "#to_bson_key" do let(:obj) { BSON::Int64.new(Integer::MAX_64BIT - 1) } let(:encoded) { (Integer::MAX_64BIT - 1) } it "returns the key as an integer" do expect(obj.to_bson_key).to eq(encoded) end end describe "#==" do let(:object) do described_class.new(1) end context "when data is identical" do let(:other_object) do described_class.new(1) end it "returns true" do expect(object).to eq(other_object) end context "other object is of another integer type" do let(:other_object) do BSON::Int32.new(1) end it "returns false" do expect(object).not_to eq(other_object) end end end context "when the data is different" do let(:other_object) do described_class.new(2) end it "returns false" do expect(object).not_to eq(other_object) end end context "when other is not a BSON integer" do it "returns false" do expect(described_class.new(1)).to_not eq('1') end end end describe "#===" do let(:object) do described_class.new(1) end context "when comparing with another BSON int64" do context "when the data is equal" do let(:other_object) do described_class.new(1) end it "returns true" do expect(object === other_object).to be true end context "other object is of another integer type" do let(:other_object) do BSON::Int32.new(1) end it "returns false" do expect(object === other_object).to be false end end end context "when the data is not equal" do let(:other_object) do described_class.new(2) end it "returns false" do expect(object === other_object).to be false end end end context "when comparing to an object id class" do it "returns false" do expect(described_class.new(1) === described_class).to be false end end context "when comparing with a string" do context "when the data is equal" do let(:other) do '1' end it "returns false" do expect(object === other).to be false end end context "when the data is not equal" do let(:other) do '2' end it "returns false" do expect(object === other).to be false end end end context "when comparing with a non-bson integer object" do it "returns false" do expect(object === []).to be false end end context "when comparing with a non int64 class" do it "returns false" do expect(object === String).to be false end end end describe '#value' do let(:obj) { described_class.new(12345) } it 'returns value passed to initializer' do expect(obj.value).to eq(12345) end end describe '#as_extended_json' do context 'canonical mode' do it 'returns $numberLong' do described_class.new(42).as_extended_json.should == {'$numberLong' => '42'} end end context 'relaxed mode' do it 'returns integer' do described_class.new(42).as_extended_json(mode: :relaxed).should == 42 end end context 'legacy mode' do it 'returns integer' do described_class.new(42).as_extended_json(mode: :legacy).should be 42 end end end end bson-ruby-4.15.0/spec/bson/integer_spec.rb000066400000000000000000000044661423026727100204260ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe Integer do describe "#to_bson" do context "when the integer is 32 bit" do let(:type) { 16.chr } let(:obj) { Integer::MAX_32BIT - 1 } let(:bson) { [ obj ].pack(BSON::Int32::PACK) } it_behaves_like "a serializable bson element" end context "when the integer is 64 bit" do let(:type) { 18.chr } let(:obj) { Integer::MAX_64BIT - 1 } let(:bson) { [ obj ].pack(BSON::Int64::PACK) } it_behaves_like "a serializable bson element" end context "when the integer is too large" do let(:integer) { Integer::MAX_64BIT + 1 } it "raises an out of range error" do expect { integer.to_bson }.to raise_error(RangeError) end end context "when the intger is too small" do let(:integer) { Integer::MIN_64BIT - 1 } it "raises an out of range error" do expect { integer.to_bson }.to raise_error(RangeError) end end end describe "#to_bson_key" do let(:obj) { Integer::MAX_32BIT - 1 } let(:encoded) { obj } it "returns the key as an integer" do expect(obj.to_bson_key).to eq(encoded) end end describe '#to_json' do it 'returns integer' do 42.to_json.should == '42' end end describe '#as_extended_json' do context 'canonical mode' do it 'returns $numberInt' do 42.as_extended_json.should == {'$numberInt' => '42'} end end context 'relaxed mode' do it 'returns integer' do 42.as_extended_json(mode: :relaxed).should be 42 end end context 'legacy mode' do it 'returns integer' do 42.as_extended_json(mode: :legacy).should be 42 end end end end bson-ruby-4.15.0/spec/bson/json_spec.rb000066400000000000000000000023431423026727100177320ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::JSON do describe "#to_json" do let(:klass) do Class.new do include BSON::JSON def as_json(*args) { :test => "value" } end end end context "when provided no arguments" do let(:json) do klass.new.to_json end it "returns the object as json" do expect(json).to eq("{\"test\":\"value\"}") end end context "when provided arguments" do let(:json) do klass.new.to_json(:test) end it "returns the object as json" do expect(json).to eq("{\"test\":\"value\"}") end end end end bson-ruby-4.15.0/spec/bson/max_key_spec.rb000066400000000000000000000033331423026727100204160ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::MaxKey do describe "#==" do context "when the objects are equal" do let(:other) { described_class.new } it "returns true" do expect(subject).to eq(other) end end context "when the other object is not a max_key" do it "returns false" do expect(subject).to_not eq("test") end end end describe "#>" do it "always returns true" do expect(subject > Integer::MAX_64BIT).to be true end end describe "#<" do it "always returns false" do expect(subject < Integer::MAX_64BIT).to be false end end describe "#as_json" do let(:object) do described_class.new end it "returns the binary data plus type" do expect(object.as_json).to eq({ "$maxKey" => 1 }) end it_behaves_like "a JSON serializable object" end describe "#to_bson/#from_bson" do let(:type) { 127.chr } let(:obj) { described_class.new } let(:bson) { BSON::NO_VALUE } it_behaves_like "a bson element" it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end end bson-ruby-4.15.0/spec/bson/min_key_spec.rb000066400000000000000000000033331423026727100204140ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::MinKey do describe "#as_json" do let(:object) do described_class.new end it "returns the binary data plus type" do expect(object.as_json).to eq({ "$minKey" => 1 }) end it_behaves_like "a JSON serializable object" end describe "#==" do context "when the objects are equal" do let(:other) { described_class.new } it "returns true" do expect(subject).to eq(other) end end context "when the other object is not a max_key" do it "returns false" do expect(subject).to_not eq("test") end end end describe "#>" do it "always returns false" do expect(subject > Integer::MAX_64BIT).to be false end end describe "#<" do it "always returns true" do expect(subject < Integer::MAX_64BIT).to be true end end describe "#to_bson/#from_bson" do let(:type) { 255.chr } let(:obj) { described_class.new } let(:bson) { BSON::NO_VALUE } it_behaves_like "a bson element" it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end end bson-ruby-4.15.0/spec/bson/nil_class_spec.rb000066400000000000000000000016031423026727100207260ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe NilClass do describe "#to_bson/#from_bson" do let(:type) { 10.chr } let(:obj) { nil } let(:bson) { BSON::NO_VALUE } it_behaves_like "a bson element" it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end end bson-ruby-4.15.0/spec/bson/object_id_spec.rb000066400000000000000000000277471423026727100207220ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" require "yaml" describe BSON::ObjectId do describe "#==" do context "when data is identical" do let(:time) do Time.now end let(:object_id) do described_class.from_time(time) end let(:other_id) do described_class.from_time(time) end it "returns true" do expect(object_id).to eq(other_id) end end context "when the data is different" do let(:time) do Time.now end let(:object_id) do described_class.from_time(time) end it "returns false" do expect(object_id).to_not eq(described_class.new) end end context "when other is not an object id" do it "returns false" do expect(described_class.new).to_not eq(nil) end end end describe "#===" do let(:object_id) do described_class.new end context "when comparing with another object id" do context "when the data is equal" do let(:other) do described_class.from_string(object_id.to_s) end it "returns true" do expect(object_id === other).to be true end end context "when the data is not equal" do let(:other) do described_class.new end it "returns false" do expect(object_id === other).to be false end end end context "when comparing to an object id class" do it "returns false" do expect(object_id === BSON::ObjectId).to be false end end context "when comparing with a string" do context "when the data is equal" do let(:other) do object_id.to_s end it "returns true" do expect(object_id === other).to be true end end context "when the data is not equal" do let(:other) do described_class.new.to_s end it "returns false" do expect(object_id === other).to be false end end end context "when comparing with a non string or object id" do it "returns false" do expect(object_id === "test").to be false end end context "when comparing with a non object id class" do it "returns false" do expect(object_id === String).to be false end end end describe "#<" do let(:object_id) do described_class.from_time(Time.utc(2012, 1, 1)) end let(:other_id) do described_class.from_time(Time.utc(2012, 1, 30)) end context "when the generation time before the other" do it "returns true" do expect(object_id < other_id).to be true end end context "when the generation time is after the other" do it "returns false" do expect(other_id < object_id).to be false end end end describe "#>" do let(:object_id) do described_class.from_time(Time.utc(2012, 1, 1)) end let(:other_id) do described_class.from_time(Time.utc(2012, 1, 30)) end context "when the generation time before the other" do it "returns false" do expect(object_id > other_id).to be false end end context "when the generation time is after the other" do it "returns true" do expect(other_id > object_id).to be true end end end describe "#<=>" do let(:object_id) do described_class.from_time(Time.utc(2012, 1, 1)) end let(:other_id) do described_class.from_time(Time.utc(2012, 1, 30)) end context "when the generation time before the other" do it "returns -1" do expect(object_id <=> other_id).to eq(-1) end end context "when the generation time is after the other" do it "returns false" do expect(other_id <=> object_id).to eq(1) end end end describe "#as_json" do let(:object) do described_class.new end it "returns the object id with $oid key" do expect(object.as_json).to eq({ "$oid" => object.to_s }) end it_behaves_like "a JSON serializable object" end describe "::BSON_TYPE" do it "returns 0x07" do expect(BSON::ObjectId::BSON_TYPE).to eq(7.chr) end end describe "#bson_type" do let(:code) do described_class.new end it "returns 0x0D" do expect(code.bson_type).to eq(BSON::ObjectId::BSON_TYPE) end end describe "#eql" do context "when data is identical" do let(:time) do Time.now end let(:object_id) do described_class.from_time(time) end let(:other_id) do described_class.from_time(time) end it "returns true" do expect(object_id).to eql(other_id) end end context "when the data is different" do let(:time) do Time.now end let(:object_id) do described_class.from_time(time) end it "returns false" do expect(object_id).to_not eql(described_class.new) end end context "when other is not an object id" do it "returns false" do expect(described_class.new).to_not eql(nil) end end end describe ".from_string" do context "when the string is valid" do let(:string) do "4e4d66343b39b68407000001" end let(:object_id) do described_class.from_string(string) end it "initializes with the string's bytes" do expect(object_id.to_s).to eq(string) end end context "when the string is not valid" do it "raises an error" do expect { described_class.from_string("asadsf") }.to raise_error(BSON::ObjectId::Invalid) end end end describe ".from_time" do context "when no unique option is provided" do let(:time) do Time.at((Time.now.utc - 64800).to_i).utc end let(:object_id) do described_class.from_time(time) end it "sets the generation time" do expect(object_id.generation_time).to eq(time) end it "does not include process or sequence information" do expect(object_id.to_s =~ /\A[0-9a-f]{8}[0]{16}\Z/).to be_truthy end end context "when a unique option is provided" do let(:time) do Time.at((Time.now.utc - 64800).to_i).utc end let(:object_id) do described_class.from_time(time, :unique => true) end let(:non_unique) do described_class.from_time(time, :unique => true) end it "creates a new unique object id" do expect(object_id).to_not eq(non_unique) end end end describe "#generation_time" do let(:time) do Time.utc(2013, 1, 1) end let(:object_id) do described_class.from_time(time) end it "returns the generation time" do expect(object_id.generation_time).to eq(time) end end describe "#hash" do let(:object_id) do described_class.new end it "returns a hash of the raw bytes" do expect(object_id.hash).to eq(object_id.to_bson.to_s.hash) end end describe "#initialize" do it "does not generate duplicate ids" do 100000.times do expect(BSON::ObjectId.new).to_not eq(BSON::ObjectId.new) end end end describe "#clone" do context "when the data has not been generated yet" do let!(:object_id) do described_class.new end let!(:clone) do object_id.clone end it "generates and copies the data" do expect(clone).to eq(object_id) end end context "when the data has been generated" do let!(:object_id) do described_class.new end let(:clone) do object_id.clone end before do object_id.to_s end it "copies the data" do expect(clone).to eq(object_id) end end end describe "#inspect" do let(:object_id) do described_class.new end it "returns the inspection with the object id to_s" do expect(object_id.inspect).to eq("BSON::ObjectId('#{object_id.to_s}')") end it "returns a string that evaluates into an equivalent object id" do expect(eval object_id.inspect).to eq object_id end end describe ".legal?" do context "when the string is too short to be an object id" do it "returns false" do expect(described_class).to_not be_legal("a" * 23) end end context "when the string contains invalid hex characters" do it "returns false" do expect(described_class).to_not be_legal("y" + "a" * 23) end end context "when the string is a valid object id" do it "returns true" do expect(described_class).to be_legal("a" * 24) end end context "when the string contains newlines" do it "returns false" do expect(described_class).to_not be_legal("\n\n" + "a" * 24 + "\n\n") end end context "when checking against another object id" do let(:object_id) do described_class.new end it "returns true" do expect(described_class).to be_legal(object_id) end end end describe "#marshal_dump" do let(:object_id) do described_class.new end let(:dumped) do Marshal.dump(object_id) end it "dumps the raw bytes data" do expect(Marshal.load(dumped)).to eq(object_id) end end describe "#marshal_load" do context "when the object id was dumped in the old format" do let(:legacy) do "\x04\bo:\x13BSON::ObjectId\x06:\n" + "@data[\x11iUi\x01\xE2i,i\x00i\x00i\x00i\x00i\x00i\x00i\x00i\x00i\x00" end let(:object_id) do Marshal.load(legacy) end let(:expected) do described_class.from_time(Time.utc(2013, 1, 1)) end it "properly loads the object id" do expect(object_id).to eq(expected) end it "removes the bad legacy data" do object_id.to_bson expect(object_id.instance_variable_get(:@data)).to be_nil end end end describe "#to_bson/#from_bson" do let(:time) { Time.utc(2013, 1, 1) } let(:type) { 7.chr } let(:obj) { described_class.from_time(time) } let(:bson) { obj.to_bson.to_s } it_behaves_like "a bson element" it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end describe "#to_s" do let(:time) do Time.utc(2013, 1, 1) end let(:expected) do "50e227000000000000000000" end let(:object_id) do described_class.from_time(time) end it "returns a hex string representation of the id" do expect(object_id.to_s).to eq(expected) end it "returns the string in UTF-8" do expect(object_id.to_s.encoding).to eq(Encoding.find(BSON::UTF8)) end it "converts to a readable yaml string" do expect(YAML.dump(object_id.to_s)).to include(expected) end end context "when the class is loaded" do let(:registered) do BSON::Registry.get(BSON::ObjectId::BSON_TYPE, 'field') end it "registers the type" do expect(registered).to eq(described_class) end end context "when the ids are used as keys" do let(:object_id) do described_class.new end let(:hash) do { object_id => 1 } end it "raises an exception on serialization" do expect { hash.to_bson }.to raise_error(BSON::InvalidKey) end end end bson-ruby-4.15.0/spec/bson/object_spec.rb000066400000000000000000000015041423026727100202250ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::Object do describe "#to_bson_key" do let(:object) do 1..3 end it "raises an exception" do expect { object.to_bson_key }.to raise_error(BSON::InvalidKey) end end end bson-ruby-4.15.0/spec/bson/open_struct_spec.rb000066400000000000000000000077171423026727100213400ustar00rootroot00000000000000# Copyright (C) 2016-2020 MongoDB Inc. # # 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. require "spec_helper" describe OpenStruct do describe "#to_bson" do let(:type) { 3.chr } it_behaves_like "a bson element" context "when the struct is a single level" do let(:obj) do described_class.new({"key" => "value" }) end let(:bson) do "#{20.to_bson.to_s}#{String::BSON_TYPE}key#{BSON::NULL_BYTE}" + "#{6.to_bson.to_s}value#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}" end it_behaves_like "a serializable bson element" end context "when the struct has invalid keys" do let(:obj) do described_class.new({ "$testing" => "value" }) end context "when validating keys" do context "when validating globally" do before do BSON::Config.validating_keys = true end after do BSON::Config.validating_keys = false end it "raises an error" do expect { obj.to_bson }.to raise_error(BSON::String::IllegalKey) end context "when the struct contains an array of documents containing invalid keys" do let(:obj) do described_class.new({ "array" => [{ "$testing" => "value" }] }) end it "raises an error" do expect { obj.to_bson }.to raise_error(BSON::String::IllegalKey) end end end context "when validating locally" do it "raises an error" do expect { obj.to_bson(BSON::ByteBuffer.new, true) }.to raise_error(BSON::String::IllegalKey) end context "when the struct contains an array of documents containing invalid keys" do let(:obj) do described_class.new({ "array" => [{ "$testing" => "value" }] }) end it "raises an error" do expect { obj.to_bson(BSON::ByteBuffer.new, true) }.to raise_error(BSON::String::IllegalKey) end end end end context "when not validating keys" do let(:bson) do "#{25.to_bson.to_s}#{String::BSON_TYPE}$testing#{BSON::NULL_BYTE}" + "#{6.to_bson.to_s}value#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}" end it "serializes the struct" do expect(obj.to_bson.to_s).to eq(bson) end context "when the struct contains an array of documents containing invalid keys" do let(:obj) do described_class.new({ "array" => [{ "$testing" => "value" }] }) end let(:bson) do "#{45.to_bson.to_s}#{Array::BSON_TYPE}array#{BSON::NULL_BYTE}" + "#{[{ "$testing" => "value" }].to_bson.to_s}#{BSON::NULL_BYTE}" end it "serializes the struct" do expect(obj.to_bson.to_s).to eq(bson) end end end end context "when the struct is embedded" do let(:obj) do described_class.new({ "field" => OpenStruct.new({ "key" => "value" })}) end let(:bson) do "#{32.to_bson.to_s}#{Hash::BSON_TYPE}field#{BSON::NULL_BYTE}" + "#{20.to_bson.to_s}#{String::BSON_TYPE}key#{BSON::NULL_BYTE}" + "#{6.to_bson.to_s}value#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}" end it_behaves_like "a serializable bson element" end end end bson-ruby-4.15.0/spec/bson/raw_spec.rb000066400000000000000000000355261423026727100175630ustar00rootroot00000000000000require 'spec_helper' describe Regexp::Raw do let(:pattern) { '\W+' } let(:options) { '' } let(:bson) { "#{pattern}#{BSON::NULL_BYTE}#{options}#{BSON::NULL_BYTE}" } describe "#as_json" do let(:object) do described_class.new(pattern, 'im') end it "returns the legacy serialization including regex pattern and options" do expect(object.as_json).to eq({ "$regex" => "\\W+", "$options" => "im" }) end it_behaves_like "a JSON serializable object" end describe '#as_extended_json' do let(:object) do described_class.new(pattern, 'im') end context 'legacy mode' do it "returns the legacy serialization including regex pattern and options" do expect(object.as_extended_json(mode: :legacy)).to eq({ "$regex" => "\\W+", "$options" => "im" }) end end context 'canonical/relaxed mode' do it "returns the extended json 2.0 serialization" do expect(object.as_extended_json).to eq( "$regularExpression" => {'pattern' => "\\W+", "options" => "im"} ) end end end describe "#to_bson/#from_bson" do let(:options) { 'ilmsux' } let(:obj) { described_class.new(pattern, options) } let(:type) { 11.chr } let(:bson) { "#{pattern}#{BSON::NULL_BYTE}#{options}#{BSON::NULL_BYTE}" } let(:klass) { ::Regexp } it_behaves_like "a bson element" it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end describe "#initialize" do let(:object) do described_class.new(pattern, options) end context "when options are not passed" do it "sets the options on the raw regex" do expect(object.options). to eq(options) end context "When the raw regexp is compiled" do let(:regexp) do object.compile end it "sets the options on the compiled regexp object" do expect(regexp.options).to eq(0) end end end context "when options are passed" do context "when options are an Integer" do let(:options) { ::Regexp::EXTENDED } it "sets the options on the raw regex" do expect(object.options). to eq(options) end context "When the raw regexp is compiled" do let(:regexp) do object.compile end it "sets the options on the compiled regexp object" do expect(regexp.options).to eq(options) end end end context "when options are a String" do let(:options) { 'x' } it "sets the options on the raw regex" do expect(object.options). to eq(options) end context "When the raw regexp is compiled" do let(:regexp) do object.compile end it "sets the options on the compiled regexp object" do expect(regexp.options).to eq(::Regexp::EXTENDED) end end end end context 'when options are not passed' do let(:object) do described_class.new(pattern) end it "sets no options on the raw regex" do expect(object.options). to eq('') end context "When the raw regexp is compiled" do let(:regexp) do object.compile end it "sets the options on the compiled regexp object" do expect(regexp.options).to eq(0) end end end end describe "#from_bson" do let(:obj) { ::Regexp.from_bson(io) } let(:io) { BSON::ByteBuffer.new(bson) } it "deserializes to a Regexp::Raw object" do expect(obj).to be_a(Regexp::Raw) end it "deserializes the pattern" do expect(obj.pattern).to eq(pattern) end context "when there are no options" do it "does not set any options on the raw regexp object" do expect(obj.options).to eq(options) end end context "when there are options" do context "when there is the i ignorecase option" do let(:options) { 'i' } it "deserializes the pattern" do expect(obj.pattern).to eq(pattern) end it "sets the i option on the raw regexp object" do expect(obj.options).to eq(options) end end context "when there is the l locale dependent option" do let(:options) { 'l' } it "deserializes the pattern" do expect(obj.pattern).to eq(pattern) end it "sets the l option on the raw regexp object" do expect(obj.options).to eq(options) end end context "when there is the m multiline option" do let(:options) { 'm' } it "deserializes the pattern" do expect(obj.pattern).to eq(pattern) end it "sets the m option on the raw regexp object" do expect(obj.options).to eq(options) end end context "when there is the s dotall option" do let(:options) { 's' } it "deserializes the pattern" do expect(obj.pattern).to eq(pattern) end it "sets the s option on the raw regexp object" do expect(obj.options).to eq(options) end end context "when there is the u match unicode option" do let(:options) { 'u' } it "deserializes the pattern" do expect(obj.pattern).to eq(pattern) end it "sets the u option on the raw regexp object" do expect(obj.options).to eq(options) end end context "when there is the x verbose option" do let(:options) { 'x' } it "deserializes the pattern" do expect(obj.pattern).to eq(pattern) end it "sets the x option on the raw regexp object" do expect(obj.options).to eq(options) end end context "when all options are set" do let(:options) { 'ilmsux' } it "deserializes the pattern" do expect(obj.pattern).to eq(pattern) end it "sets all options on the raw regexp object" do expect(obj.options).to eq(options) end end end end context "when a method is called on a Raw regexp object" do let(:obj) { ::Regexp.from_bson(io) } let(:io) { BSON::ByteBuffer.new(bson) } it "forwards the method call on to the compiled Ruby Regexp object" do expect(obj.source).to eq(pattern) end end context "when respond_to? is called on the Raw Regexp object" do let(:obj) { Regexp::Raw.new(pattern, options) } context "when include_private is false" do it "does not consider private methods" do expect(obj.respond_to?(:initialize_copy)).to eq(false) end end context "when include private is true" do it "considers private methods" do expect(obj.respond_to?(:initialize_copy, true)).to eq(true) end end context "when include_private is not specified" do it "does not consider private methods" do expect(obj.respond_to?(:initialize_copy)).to eq(false) end end end context "#to_bson" do let(:obj) { Regexp::Raw.new(pattern, options) } let(:options) { '' } let(:bson) { "#{pattern}#{BSON::NULL_BYTE}#{options}#{BSON::NULL_BYTE}" } let(:serialized) { obj.to_bson.to_s } it "serializes the pattern" do expect(serialized).to eq(bson) end context "where there are no options" do it "does not set any options on the bson regex object" do expect(serialized).to eq(bson) end end context "when there are options" do context "when options are specified as an Integer" do let(:options) { ::Regexp::EXTENDED } let(:bson) { "#{pattern}#{BSON::NULL_BYTE}mx#{BSON::NULL_BYTE}" } it "sets the option on the serialized bson object" do expect(serialized).to eq(bson) end end context "when there is the i ignorecase option" do let(:options) { 'i' } it "sets the option on the serialized bson object" do expect(serialized).to eq(bson) end end context "when there is the l locale dependent option" do let(:options) { 'l' } it "sets the option on the serialized bson object" do expect(serialized).to eq(bson) end end context "when there is the m multiline option" do let(:options) { 'm' } it "sets the option on the serialized bson object" do expect(serialized).to eq(bson) end end context "when there is the s dotall option" do let(:options) { 's' } it "sets the option on the serialized bson object" do expect(serialized).to eq(bson) end end context "when there is the u match unicode option" do let(:options) { 'u' } it "sets the option on the serialized bson object" do expect(serialized).to eq(bson) end end context "when there is the x verbose option" do let(:options) { 'x' } it "sets the option on the serialized bson object" do expect(serialized).to eq(bson) end end context "when all options are set" do let(:options) { 'ilmsux' } it "sets all options on the serialized bson object" do expect(serialized).to eq(bson) end context "when the options are not provided in alphabetical order" do let(:options) { 'mislxu' } let(:bson) { "#{pattern}#{BSON::NULL_BYTE}ilmsux#{BSON::NULL_BYTE}" } it "serializes the options in alphabetical order" do expect(serialized).to eq(bson) end end end end end describe "#compile" do let(:obj) { Regexp.from_bson(io) } let(:io) { BSON::ByteBuffer.new(bson) } let(:ruby_regexp) { obj.compile } it "sets the pattern on the Ruby Regexp object" do expect(obj.pattern).to eq(ruby_regexp.source) end context "when there are no options set" do it "does not set any options on the Ruby Regexp object" do expect(ruby_regexp.options).to eq(0) end end context "when there are options set" do context "when there is the i ignorecase option" do let(:options) { 'i' } it "sets the i option on the Ruby Regexp object" do expect(ruby_regexp.options).to eq(::Regexp::IGNORECASE) end end context "when there is the l locale dependent option" do let(:options) { 'l' } it "does not set an option on the Ruby Regexp object" do expect(ruby_regexp.options).to eq(0) end end context "when there is the m multiline option" do let(:options) { 'm' } it "does not set an option on the Ruby Regexp object" do expect(ruby_regexp.options).to eq(0) end end context "when there is the s dotall option" do let(:options) { 's' } # s in a bson regex maps to a Ruby Multiline Regexp option it "sets the m option on the Ruby Regexp object" do expect(ruby_regexp.options).to eq(::Regexp::MULTILINE) end end context "when there is the u match unicode option" do let(:options) { 'u' } it "does not set an option on the Ruby Regexp object" do expect(ruby_regexp.options).to eq(0) end end context "when there is the x verbose option" do let(:options) { 'x' } it "sets the x option on the Ruby Regexp object" do expect(ruby_regexp.options).to eq(::Regexp::EXTENDED) end end context "when all options are set" do let(:options) { 'ilmsux' } # s in a bson regex maps to a Ruby Multiline Regexp option it "sets the i, m, and x options on the Ruby Regexp object" do expect(ruby_regexp.options).to eq(::Regexp::IGNORECASE | ::Regexp::MULTILINE | ::Regexp::EXTENDED) end end end end context "when a Regexp::Raw object is roundtripped" do let(:obj) { Regexp::Raw.new(pattern, options) } let(:serialized) { obj.to_bson.to_s } let(:roundtripped) { Regexp.from_bson(BSON::ByteBuffer.new(serialized)) } it "roundtrips the pattern" do expect(roundtripped.pattern).to eq(pattern) end context "when there are no options" do let(:options) { '' } it "does not set any options on the roundtripped Regexp::Raw object" do expect(roundtripped.options).to eq(options) end end context "when there are options set" do context "when there is the i ignorecase option" do let(:options) { 'i' } it "sets the i option on the roundtripped Regexp::Raw object" do expect(roundtripped.options).to eq(options) end end context "when there is the l locale dependent option" do let(:options) { 'l' } it "sets the l option on the roundtripped Regexp::Raw object" do expect(roundtripped.options).to eq(options) end end context "when there is the m multiline option" do let(:options) { 'm' } it "sets the m option on the roundtripped Regexp::Raw object" do expect(roundtripped.options).to eq(options) end end context "when there is the s dotall option" do let(:options) { 's' } it "sets the s option on the roundtripped Regexp::Raw object" do expect(roundtripped.options).to eq(options) end end context "when there is the u match unicode option" do let(:options) { 'u' } it "sets the u option on the roundtripped Regexp::Raw object" do expect(roundtripped.options).to eq(options) end end context "when there is the x verbose option" do let(:options) { 'x' } it "sets the x option on the roundtripped Regexp::Raw object" do expect(roundtripped.options).to eq(options) end end context "when all options are set" do let(:options) { 'ilmsux' } it "sets all the options on the roundtripped Regexp::Raw object" do expect(roundtripped.options).to eq(options) end context "when the options are passed in not in alphabetical order" do let(:options) { 'sumlxi' } it "sets all the options on the roundtripped Regexp::Raw object in order" do expect(roundtripped.options).to eq(options.chars.sort.join) end end end end end describe 'yaml loading' do let(:regexp) { described_class.new('hello.world', 's') } it 'round-trips' do actual = if YAML.respond_to?(:unsafe_load) # In psych >= 4.0.0 `load` is basically an alias to `safe_load`, # which will fail here. YAML.unsafe_load(regexp.to_yaml) else YAML.load(regexp.to_yaml) end actual.pattern.should == 'hello.world' actual.options.should == 's' actual.compile.should =~ "hello\nworld" end end end bson-ruby-4.15.0/spec/bson/regexp_spec.rb000066400000000000000000000107111423026727100202510ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe Regexp do describe "#as_json" do let(:object) do /\W+/i end it "returns the binary data plus type" do expect(object.as_json).to eq( { "$regex" => "\\W+", "$options" => "im" } ) end it_behaves_like "a JSON serializable object" end describe "#to_bson/#from_bson" do let(:type) { 11.chr } let(:obj) { /test/ } let(:io) do BSON::ByteBuffer.new(bson) end let(:regex) do described_class.from_bson(io) end let(:result) do regex.compile end it_behaves_like "a bson element" context "when calling normal regexp methods on a Regexp::Raw" do let :obj do /\d+/ end let(:bson) { "#{obj.source}#{BSON::NULL_BYTE}m#{BSON::NULL_BYTE}" } it_behaves_like "a serializable bson element" it "runs the method on the Regexp object" do expect(regex.match('6')).not_to be_nil end end context "when the regexp has no options" do let(:obj) { /\d+/ } # Ruby always has a BSON regex's equivalent of multiline on # http://www.regular-expressions.info/modifiers.html let(:bson) { "#{obj.source}#{BSON::NULL_BYTE}m#{BSON::NULL_BYTE}" } it_behaves_like "a serializable bson element" it "deserializes from bson" do expect(result).to eq(obj) end end context "when the regexp has options" do context "when ignoring case" do let(:obj) { /\W+/i } let(:bson) { "#{obj.source}#{BSON::NULL_BYTE}im#{BSON::NULL_BYTE}" } it_behaves_like "a serializable bson element" it "deserializes from bson" do expect(result).to eq(obj) end end context "when matching multiline" do let(:obj) { /\W+/m } let(:bson) { "#{obj.source}#{BSON::NULL_BYTE}ms#{BSON::NULL_BYTE}" } it_behaves_like "a serializable bson element" it "deserializes from bson" do expect(result).to eq(obj) end end context "when matching extended" do let(:obj) { /\W+/x } let(:bson) { "#{obj.source}#{BSON::NULL_BYTE}mx#{BSON::NULL_BYTE}" } it_behaves_like "a serializable bson element" it "deserializes from bson" do expect(result).to eq(obj) end end context "when all options are present" do let(:obj) { /\W+/xim } let(:bson) { "#{obj.source}#{BSON::NULL_BYTE}imsx#{BSON::NULL_BYTE}" } it_behaves_like "a serializable bson element" it "deserializes from bson" do expect(result).to eq(obj) end end context "when the regexp options contains a null byte" do let(:regexp) do Regexp::Raw.new("pattern", "options\x00") end it "raises an error" do expect do regexp end.to raise_error(BSON::Error::InvalidRegexpPattern, /Regexp options cannot contain a null byte/) end end context "when the regexp options is an integer" do let(:regexp) do Regexp::Raw.new("pattern", 1) end it "doesn't raise an error" do expect do regexp end.to_not raise_error end end context "when the regexp options is an invalid type" do let(:regexp) do Regexp::Raw.new("pattern", [2]) end it "raises an error" do expect do regexp end.to raise_error(ArgumentError, /Regexp options must be a String, Symbol, or Integer/) end end end context "when the pattern contains a null byte" do let(:regexp) do Regexp::Raw.new("pattern\x00", "options") end it "raises an error" do expect do regexp end.to raise_error(BSON::Error::InvalidRegexpPattern, /Regexp pattern cannot contain a null byte/) end end end end bson-ruby-4.15.0/spec/bson/registry_spec.rb000066400000000000000000000023271423026727100206330ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::Registry do describe ".get" do context "when the type has a correspoding class" do before do described_class.register(BSON::MinKey::BSON_TYPE, BSON::MinKey) end let(:klass) do described_class.get(BSON::MinKey::BSON_TYPE, "field") end it "returns the class" do expect(klass).to eq(BSON::MinKey) end end context "when the type has no corresponding class" do it "raises an error" do expect { described_class.get(25.chr, "field") }.to raise_error(BSON::Registry::UnsupportedType) end end end end bson-ruby-4.15.0/spec/bson/string_spec.rb000066400000000000000000000063121423026727100202670ustar00rootroot00000000000000# encoding: utf-8 # Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe String do describe "#to_bson/#from_bson" do let(:type) { 2.chr } let(:obj) { "test" } let(:bson) { "#{5.to_bson.to_s}test#{BSON::NULL_BYTE}" } it_behaves_like "a bson element" it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end describe "#to_bson_object_id" do context "when the string has 12 characters" do let(:string) do "123456789012" end let(:converted) do string.to_bson_object_id end it "returns the array as a string" do expect(converted).to eq(string) end end context "when the array does not have 12 elements" do it "raises an exception" do expect { "test".to_bson_object_id }.to raise_error(BSON::ObjectId::Invalid) end end end context "when the class is loaded" do let(:registered) do BSON::Registry.get(String::BSON_TYPE, 'field') end it "registers the type" do expect(registered).to eq(String) end end describe "#to_bson_key" do let(:string) { "test" } let(:encoded) { string.to_s } it "returns the encoded string" do expect(string.to_bson_key).to eq(encoded) end end describe "#to_hex_string" do let(:string) do "testing123" end it "converts the string to hex" do expect(string.to_hex_string).to eq("74657374696e67313233") end end describe "#to_bson_key" do context "when validating keys" do context "when validating globally" do before do BSON::Config.validating_keys = true end after do BSON::Config.validating_keys = false end let(:validated) do string.to_bson_key end it_behaves_like "a validated BSON key" end context "when validating locally" do let(:validated) do string.to_bson_key(true) end it_behaves_like "a validated BSON key" end end context "when allowing invalid keys" do let(:string) do "$testing.testing" end it "allows invalid keys" do expect(string.to_bson_key).to eq(string) end end end describe '#to_bson' do context 'when string is not valid utf-8' do let(:string) do "\xfe\x00\xff".force_encoding('BINARY') end let(:expected_message) do /from ASCII-8BIT to UTF-8/ end it 'raises EncodingError' do expect do string.to_bson end.to raise_error(EncodingError, expected_message) end end end end bson-ruby-4.15.0/spec/bson/symbol_raw_spec.rb000066400000000000000000000023231423026727100211350ustar00rootroot00000000000000# Copyright (C) 2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::Symbol::Raw do describe '#==' do let(:one) { described_class.new('foo') } let(:two) { described_class.new('foo') } let(:three) { described_class.new('bar') } it 'compares equal' do one.should == two end it 'compares not equal' do one.should_not == three end end describe '#eql?' do let(:one) { described_class.new('foo') } let(:two) { described_class.new('foo') } let(:three) { described_class.new('bar') } it 'compares equal' do one.should be_eql(two) end it 'compares not equal' do one.should_not be_eql(three) end end end bson-ruby-4.15.0/spec/bson/symbol_spec.rb000066400000000000000000000063351423026727100202730ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe Symbol do describe "#bson_type" do it "returns the type for a string" do expect(:type.bson_type).to eq("type".bson_type) end end describe "#to_bson/#from_bson" do let(:type) { 2.chr } let(:obj) { :test } let(:bson) { "#{5.to_bson.to_s}test#{BSON::NULL_BYTE}" } it_behaves_like "a bson element" it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" context 'canonical deserialization' do let(:bson) do BSON::ByteBuffer.new(BSON::Symbol::Raw.new(obj).to_bson.to_s) end let(:deserialized) do described_class.from_bson(bson, mode: :bson) end it 'deserializes to BSON::Symbol::Raw' do deserialized.class.should be BSON::Symbol::Raw end it 'has the correct value' do deserialized.to_sym.should be obj end end context 'when changing bson_type' do def perform_test(bson_type_to_use) Symbol.class_eval do alias_method :bson_type_orig, :bson_type define_method(:bson_type) do bson_type_to_use end end begin yield ensure Symbol.class_eval do alias_method :bson_type, :bson_type_orig remove_method :bson_type_orig end end end let(:value) { :foo } let(:serialized) do value.to_bson.to_s end context 'when bson_type is set to symbol' do it 'serializes to BSON string' do perform_test(BSON::Symbol::BSON_TYPE) do serialized end.should == "\x04\x00\x00\x00foo\x00".force_encoding('binary') end end context 'when bson_type is set to string' do it 'serializes to BSON string' do perform_test(BSON::String::BSON_TYPE) do serialized end.should == "\x04\x00\x00\x00foo\x00".force_encoding('binary') end end end end describe "#to_bson_key" do let(:symbol) { :test } let(:encoded) { symbol } it "returns the encoded string" do expect(symbol.to_bson_key).to eq(encoded) end end describe "#to_bson_key" do context "when validating keys" do let(:symbol) do :'$testing.testing' end it "raises an exception" do expect { symbol.to_bson_key(true) }.to raise_error(BSON::String::IllegalKey) end end context "when not validating keys" do let(:symbol) do :'$testing.testing' end it "allows invalid keys" do expect(symbol.to_bson_key).to eq(symbol) end end end end bson-ruby-4.15.0/spec/bson/time_spec.rb000066400000000000000000000171631423026727100177250ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe Time do describe "#to_bson/#from_bson" do let(:type) { 9.chr } it_behaves_like "a bson element" context "when the time is post epoch" do context "when the time has no microseconds" do let(:obj) { Time.utc(2012, 1, 1, 0, 0, 0) } let(:bson) { [ (obj.to_i * 1000) + (obj.usec / 1000) ].pack(BSON::Int64::PACK) } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context "when the time has microseconds" do let(:obj) { Time.at(Time.utc(2014, 03, 22, 18, 05, 05).to_i, 505000).utc } let(:bson) { [ (obj.to_i * 1000) + (obj.usec / 1000) ].pack(BSON::Int64::PACK) } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end end context "when the time precedes epoch" do let(:obj) { Time.utc(1969, 1, 1, 0, 0, 0) } let(:bson) { [ (obj.to_f * 1000).to_i ].pack(BSON::Int64::PACK) } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end context 'when value has sub-millisecond precision' do let(:obj) { Time.utc(2012, 1, 1, 0, 0, 0, 999_999) } let(:expected_round_tripped_obj) do Time.utc(2012, 1, 1, 0, 0, 0, 999_000) end let(:round_tripped_obj) do Time.from_bson(obj.to_bson) end it 'truncates to milliseconds when round-tripping' do round_tripped_obj.should == expected_round_tripped_obj end end end describe '#as_extended_json' do context 'canonical mode' do context 'when value has sub-millisecond precision' do let(:obj) { Time.utc(2012, 1, 1, 0, 0, 0, 999_999) } let(:expected_serialization) do {'$date' => {'$numberLong' => '1325376000999'}} end let(:serialization) do obj.as_extended_json end shared_examples_for 'truncates to milliseconds when serializing' do it 'truncates to milliseconds when serializing' do serialization.should == expected_serialization end end it_behaves_like 'truncates to milliseconds when serializing' context 'when value has sub-microsecond precision' do let(:obj) { Time.utc(2012, 1, 1, 0, 0, 0, 999_999_999/1000r) } it_behaves_like 'truncates to milliseconds when serializing' end context "when the time precedes epoch" do let(:obj) { Time.utc(1960, 1, 1, 0, 0, 0, 999_999) } let(:expected_serialization) do {'$date' => {'$numberLong' => '-315619199001'}} end it_behaves_like 'truncates to milliseconds when serializing' end end end context 'relaxed mode' do context 'when value has sub-millisecond precision' do let(:obj) { Time.utc(2012, 1, 1, 0, 0, 0, 999_999) } let(:expected_serialization) do {'$date' => '2012-01-01T00:00:00.999Z'} end let(:serialization) do obj.as_extended_json(mode: :relaxed) end shared_examples_for 'truncates to milliseconds when serializing' do it 'truncates to milliseconds when serializing' do serialization.should == expected_serialization end end it_behaves_like 'truncates to milliseconds when serializing' context 'when value has sub-microsecond precision' do let(:obj) { Time.utc(2012, 1, 1, 0, 0, 0, 999_999_999/1000r) } it_behaves_like 'truncates to milliseconds when serializing' end context "when the time precedes epoch" do let(:obj) { Time.utc(1960, 1, 1, 0, 0, 0, 999_999) } let(:expected_serialization) do {'$date' => {'$numberLong' => '-315619199001'}} end it_behaves_like 'truncates to milliseconds when serializing' end end end end describe '#to_extended_json' do context 'canonical mode' do context 'when value has sub-millisecond precision' do let(:obj) { Time.utc(2012, 1, 1, 0, 0, 0, 999_999) } let(:expected_serialization) do %q`{"$date":{"$numberLong":"1325376000999"}}` end let(:serialization) do obj.to_extended_json end shared_examples_for 'truncates to milliseconds when serializing' do it 'truncates to milliseconds when serializing' do serialization.should == expected_serialization end end it_behaves_like 'truncates to milliseconds when serializing' context 'when value has sub-microsecond precision' do let(:obj) { Time.utc(2012, 1, 1, 0, 0, 0, 999_999_999/1000r) } it_behaves_like 'truncates to milliseconds when serializing' end context "when the time precedes epoch" do let(:obj) { Time.utc(1960, 1, 1, 0, 0, 0, 999_999) } let(:expected_serialization) do %q`{"$date":{"$numberLong":"-315619199001"}}` end it_behaves_like 'truncates to milliseconds when serializing' end end end context 'relaxed mode' do context 'when value has sub-millisecond precision' do let(:obj) { Time.utc(2012, 1, 1, 0, 0, 0, 999_999) } let(:expected_serialization) do %q`{"$date":"2012-01-01T00:00:00.999Z"}` end let(:serialization) do obj.to_extended_json(mode: :relaxed) end shared_examples_for 'truncates to milliseconds when serializing' do it 'truncates to milliseconds when serializing' do serialization.should == expected_serialization end end it_behaves_like 'truncates to milliseconds when serializing' context 'when value has sub-microsecond precision' do let(:obj) { Time.utc(2012, 1, 1, 0, 0, 0, 999_999_999/1000r) } it_behaves_like 'truncates to milliseconds when serializing' end end end end describe '#to_json' do context 'when value has sub-millisecond precision' do let(:obj) { Time.utc(2012, 1, 1, 0, 0, 0, 999_999) } let(:expected_serialization) do %q`"2012-01-01 00:00:00 UTC"` end let(:serialization) do obj.to_json end shared_examples_for 'truncates to milliseconds when serializing' do it 'truncates to milliseconds when serializing' do serialization.should == expected_serialization end end it_behaves_like 'truncates to milliseconds when serializing' context 'when value has sub-microsecond precision' do let(:obj) { Time.utc(2012, 1, 1, 0, 0, 0, 999_999_999/1000r) } it_behaves_like 'truncates to milliseconds when serializing' end context "when the time precedes epoch" do let(:obj) { Time.utc(1960, 1, 1, 0, 0, 0, 999_999) } let(:expected_serialization) do %q`"1960-01-01 00:00:00 UTC"` end it_behaves_like 'truncates to milliseconds when serializing' end end end end bson-ruby-4.15.0/spec/bson/time_with_zone_spec.rb000066400000000000000000000042711423026727100220070ustar00rootroot00000000000000# Copyright (C) 2018-2020 MongoDB Inc. # # 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. require "spec_helper" context 'when ActiveSupport support is enabled' do before do unless SpecConfig.instance.active_support? skip "ActiveSupport support is not enabled" end end describe 'ActiveSupport::TimeWithZone' do let(:cls) { ActiveSupport::TimeWithZone } it "shares BSON type with Time" do # ActiveSupport::TimeWithZone#new has no 0-argument version obj = Time.now.in_time_zone("UTC") expect(obj.bson_type).to eq(Time::BSON_TYPE) end shared_examples_for 'deserializes as expected' do it 'deserializes to UTC' do # Time zone information is lost during serialization - the time # is always serialized in UTC. rt_obj = Time.from_bson(obj.to_bson) expect(rt_obj.zone).to eq('UTC') end it 'deserializes to an equal object' do rt_obj = Time.from_bson(obj.to_bson) expect(rt_obj).to eq(obj) end end describe "#to_bson" do context "when the TimeWithZone is not in UTC" do let(:obj) { Time.utc(2012, 12, 12, 0, 0, 0).in_time_zone("Pacific Time (US & Canada)") } let(:bson) { [ (obj.utc.to_f * 1000).to_i ].pack(BSON::Int64::PACK) } it_behaves_like "a serializable bson element" it_behaves_like 'deserializes as expected' end context "when the TimeWithZone is in UTC" do let(:obj) { Time.utc(2012, 1, 1, 0, 0, 0).in_time_zone("UTC") } let(:bson) { [ (obj.utc.to_f * 1000).to_i ].pack(BSON::Int64::PACK) } it_behaves_like "a serializable bson element" it_behaves_like 'deserializes as expected' end end end end bson-ruby-4.15.0/spec/bson/timestamp_spec.rb000066400000000000000000000063261423026727100207710ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::Timestamp do describe "#==" do let(:timestamp) do described_class.new(1, 10) end context "when the objects are equal" do let(:other) { described_class.new(1, 10) } it "returns true" do expect(timestamp).to eq(other) end end context "when the objects are not equal" do let(:other) { described_class.new(1, 15) } it "returns false" do expect(timestamp).to_not eq(other) end end context "when the other object is not a timestamp" do it "returns false" do expect(timestamp).to_not eq("test") end end end describe "#<=>" do let(:timestamp) do described_class.new(1, 10) end context "when the objects are equal" do let(:other) { described_class.new(1, 10) } it "returns 0" do expect(timestamp).to eq(other) expect(timestamp < other).to be(false) expect(timestamp > other).to be(false) expect(timestamp >= other).to be(true) expect(timestamp <= other).to be(true) end end context "when the first object is less than the second" do let(:other) { described_class.new(1, 15) } it "returns -1" do expect(timestamp <=> other).to be(-1) expect(timestamp < other).to be(true) expect(timestamp > other).to be(false) expect(timestamp >= other).to be(false) expect(timestamp <= other).to be(true) end end context "when the first object is greater than the second" do let(:other) { described_class.new(1, 5) } it "returns 1" do expect(timestamp <=> other).to be(1) expect(timestamp < other).to be(false) expect(timestamp > other).to be(true) expect(timestamp >= other).to be(true) expect(timestamp <= other).to be(false) end end context "when the other object is not a timestamp" do it "raises an ArgumentError" do expect { timestamp < 1 }.to raise_exception(ArgumentError) end end end describe "#as_json" do let(:object) do described_class.new(10, 50) end it "returns the binary data plus type" do expect(object.as_json).to eq({"$timestamp" => { "t" => 10, "i" => 50 } }) end it_behaves_like "a JSON serializable object" end describe "#to_bson/#from_bson" do let(:type) { 17.chr } let(:obj) { described_class.new(1, 10) } let(:bson) { [ 10, 1 ].pack(BSON::Int32::PACK * 2) } it_behaves_like "a bson element" it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end end bson-ruby-4.15.0/spec/bson/true_class_spec.rb000066400000000000000000000014741423026727100211310ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe TrueClass do describe "#to_bson" do let(:obj) { true } let(:bson) { 1.chr } let(:type) { 8.chr } it_behaves_like "a bson element" it_behaves_like "a serializable bson element" end end bson-ruby-4.15.0/spec/bson/undefined_spec.rb000066400000000000000000000016311423026727100207210ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON::Undefined do describe "#to_bson/#from_bson" do let(:type) { 6.chr } let(:obj) { described_class.new } let(:bson) { BSON::NO_VALUE } it_behaves_like "a bson element" it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" end end bson-ruby-4.15.0/spec/bson_spec.rb000066400000000000000000000025571423026727100167700ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. require "spec_helper" describe BSON do describe ".ObjectId" do let(:string) { "4e4d66343b39b68407000001" } it "returns an BSON::ObjectId from given string" do expect(described_class::ObjectId(string)).to be_a BSON::ObjectId expect(described_class::ObjectId(string)).to eq BSON::ObjectId.from_string(string) end end describe "::BINARY" do it "returns BINARY" do expect(BSON::BINARY).to eq("BINARY") end end describe "::NO_VAUE" do it "returns an empty string" do expect(BSON::NO_VALUE).to be_empty end end describe "::NULL_BYTE" do it "returns the char 0x00" do expect(BSON::NULL_BYTE).to eq(0.chr) end end describe "::UTF8" do it "returns UTF-8" do expect(BSON::UTF8).to eq("UTF-8") end end end bson-ruby-4.15.0/spec/runners/000077500000000000000000000000001423026727100161535ustar00rootroot00000000000000bson-ruby-4.15.0/spec/runners/common_driver.rb000066400000000000000000000220311423026727100213410ustar00rootroot00000000000000# Copyright (C) 2016-2020 MongoDB Inc. # # 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. require 'json' require 'bigdecimal' module BSON module CommonDriver # Represents a Common Driver specification test. # # @since 4.2.0 class Spec # The spec description. # # @return [ String ] The spec description. # # @since 4.2.0 attr_reader :description # The document key of the object to test. # # @return [ String ] The document key. # # @since 4.2.0 attr_reader :test_key # Instantiate the new spec. # # @example Create the spec. # Spec.new(file) # # @param [ String ] file The name of the yaml file. # # @since 4.2.0 def initialize(file) @spec = ::JSON.parse(File.read(file)) @valid = @spec['valid'] || [] @invalid = @spec['parseErrors'] || [] @description = @spec['description'] @test_key = @spec['test_key'] end # Get a list of tests that don't raise exceptions. # # @example Get the list of valid tests. # spec.valid_tests # # @return [ Array ] The list of valid Tests. # # @since 4.2.0 def valid_tests @valid_tests ||= @valid.collect do |test| BSON::CommonDriver::Test.new(self, test) end end # Get a list of tests that raise exceptions. # # @example Get the list of invalid tests. # spec.invalid_tests # # @return [ Array ] The list of invalid Tests. # # @since 4.2.0 def invalid_tests @invalid_tests ||= @invalid.collect do |test| BSON::CommonDriver::Test.new(self, test) end end # The class of the bson object to test. # # @example Get the class of the object to test. # spec.klass # # @return [ Class ] The object class. # # @since 4.2.0 def klass @klass ||= BSON.const_get(description) end end # Represents a single CommonDriver test. # # @since 4.2.0 class Test # The test description. # # @return [ String ] The test description. # # @since 4.2.0 attr_reader :description # The test subject. # # @return [ String ] The test subject. # # @since 4.2.0 attr_reader :subject # The string to use to create a Decimal128. # # @return [ String ] The string to use in creating a Decimal128 object. # # @since 4.2.0 attr_reader :string # The expected string representation of the Decimal128 object. # # @return [ String ] The object as a string. # # @since 4.2.0 attr_reader :match_string # The json representation of the object. # # @return [ Hash ] The json representation of the object. # # @since 4.2.0 attr_reader :ext_json # Instantiate the new Test. # # @example Create the test. # Test.new(test) # # @param [ CommonDriver::Spec ] spec The test specification. # @param [ Hash ] test The test specification. # # @since 4.2.0 def initialize(spec, test) @spec = spec @description = test['description'] @string = test['string'] @match_string = test['match_string'] @ext_json = ::JSON.parse(test['extjson']) if test['extjson'] @from_ext_json = test['from_extjson'].nil? ? true : test['from_extjson'] @to_ext_json = test['to_extjson'].nil? ? true : test['to_extjson'] @subject = test['subject'] @test_key = spec.test_key end # Get the reencoded document in hex format. # # @example Get the reencoded document as hex. # test.reencoded_hex # # @return [ String ] The reencoded document in hex format. # # @since 4.2.0 def reencoded_hex decoded_document.to_bson.to_s.unpack1("H*").upcase end # The object tested. # # @example Get the object for this test. # test.object # # @return [ BSON::Object ] The object. # # @since 4.2.0 def object @object ||= decoded_document[@test_key] end # The object as json, in a document with the test key. # # @example Get a document with the object at the test key. # test.document_as_json # # @return [ BSON::Document ] The json document. # # @since 4.2.0 def document_as_json { @test_key => object.as_json } end # Use the string in the extended json to instantiate the bson object. # # @example Get a bson object from the string in the extended json. # test.from_json # # @return [ BSON::Object ] The BSON object. # # @since 4.2.0 def from_json_string klass.from_string(@ext_json[@test_key][klass::EXTENDED_JSON_KEY]) end # Create an object from the given test string. # # @example # test.parse_string # # @return [ BSON::Object ] The object. # # @since 4.2.0 def parse_string klass.from_string(string) end # Attempt to create an object from an invalid string. # # @example # test.parse_invalid_string # # @raise [ Error ] Parsing an invalid string will raise an error. # # @since 4.2.0 def parse_invalid_string klass.from_string(subject) end # The class of the object being tested. # # @example # test.klass # # @return [ Class ] The object class. # # @since 4.2.0 def klass @spec.klass end # The error class of a parse error. # # @example # test.parse_error # # @return [ Class ] The parse error class. # # @since 4.2.0 def parse_error klass::InvalidRange end # Whether the object can be instantiated from extended json. # # @example Check if an object can be instantiated from the extended json. # test.from_ex_json? # # @return [ true, false ] If the object can be instantiated from # the provided extended json. # # @since 4.2.0 def from_ext_json? @ext_json && @from_ext_json end # Whether the object can be represented as extended json. # # @example Check if an object can be represented as extended json. # test.to_ext_json? # # @return [ true, false ] If the object can be represented as # extended json. # # @since 4.2.0 def to_ext_json? @ext_json && @to_ext_json end # Whether the object can be instantiated from a string. # # @example Check if an object can be instantiated from a string. # test.from_string? # # @return [ true, false ] If the object can be instantiated from a string. # # @since 4.2.0 def from_string? @string && @from_ext_json end # The expected string representation of the test object. # # @example Get the expected String representation of the test object. # test.expected_to_string # # @return [ String ] The expected string representation. # # @since 4.2.0 def expected_to_string match_string || string end # The Ruby class to which this bson object can be converted via a helper. # # @example Get the native type to which this object can be converted. # test.native_type # # @return [ Class ] The Ruby native type. # # @since 4.2.0 def native_type klass::NATIVE_TYPE end # Get the object converted to an instance of the native Ruby type. # # @example Get a native Ruby instance. # test.native_type_conversion # # @return [ Object ] An instance of the Ruby native type. # # @since 4.2.0 def native_type_conversion object.send("to_#{to_snake_case(native_type)}") end private def to_snake_case(string) string.to_s.gsub(/::/, '/'). gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). gsub(/([a-z\d])([A-Z])/,'\1_\2'). tr("-", "_"). downcase end def decoded_document @document ||= (data = [ @subject ].pack('H*') buffer = BSON::ByteBuffer.new(data) BSON::Document.from_bson(buffer)) end end end end bson-ruby-4.15.0/spec/runners/corpus.rb000066400000000000000000000106021423026727100200120ustar00rootroot00000000000000# Copyright (C) 2016-2020 MongoDB Inc. # # 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. require 'json' require 'forwardable' module BSON module Corpus # Represents a test from the driver BSON Corpus. # # @since 4.2.0 class Spec # The spec description. # # @return [ String ] The spec description. # # @since 4.2.0 attr_reader :description # The document key of the object to test. # # @return [ String ] The document key. # # @since 4.2.0 attr_reader :test_key # Instantiate the new spec. # # @example Create the spec. # Spec.new(file) # # @param [ String ] file The name of the json file. # # @since 4.2.0 def initialize(file) @spec = ::JSON.parse(File.read(file).force_encoding('utf-8')) end def description @spec['description'] end def test_key @spec['test_key'] end def valid_tests @valid_tests ||= @spec['valid']&.map do |test_spec| ValidTest.new(self, test_spec) end end def decode_error_tests @decode_error_tests ||= @spec['decodeErrors']&.map do |test_spec| DecodeErrorTest.new(self, test_spec) end end def parse_error_tests @parse_error_tests ||= @spec['parseErrors']&.map do |test_spec| ParseErrorTest.new(self, test_spec) end end # The class of the bson object to test. # # @example Get the class of the object to test. # spec.klass # # @return [ Class ] The object class. # # @since 4.2.0 def klass @klass ||= BSON.const_get(description) end end class TestBase private def decode_hex(obj) [ obj ].pack('H*') end end # Represents a single BSON Corpus test. # # @since 4.2.0 class ValidTest < TestBase extend Forwardable # Instantiate the new Test. # # @example Create the test. # Test.new(test) # # @param [ Corpus::Spec ] spec The test specification. # @param [ Hash ] test The test specification. # # @since 4.2.0 def initialize(spec, test_params) @spec = spec test_params = test_params.dup %w( description canonical_extjson relaxed_extjson degenerate_extjson converted_extjson lossy ).each do |key| instance_variable_set("@#{key}", test_params.delete(key)) end %w( canonical_bson degenerate_bson converted_bson lossy ).each do |key| if test_params.key?(key) instance_variable_set("@#{key}", decode_hex(test_params.delete(key))) end end unless test_params.empty? raise "Test params has unprocessed keys: #{test_params}" end end def_delegators :@spec, :test_key attr_reader :description, :canonical_bson, :degenerate_bson, :converted_bson, :canonical_extjson, :relaxed_extjson, :degenerate_extjson, :converted_extjson def lossy? !!@lossy end def canonical_extjson_doc ::JSON.parse(canonical_extjson) end def relaxed_extjson_doc relaxed_extjson && ::JSON.parse(relaxed_extjson) end end class DecodeErrorTest < TestBase def initialize(spec, test_params) @spec = spec @description = test_params['description'] @bson = decode_hex(test_params['bson']) end attr_reader :description, :bson end class ParseErrorTest def initialize(spec, test_params) @spec = spec @description = test_params['description'] @string = test_params['string'] end attr_reader :description, :string end end end bson-ruby-4.15.0/spec/runners/corpus_legacy.rb000066400000000000000000000172461423026727100213510ustar00rootroot00000000000000# Copyright (C) 2016-2020 MongoDB Inc. # # 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. require 'json' module BSON module CorpusLegacy # Represents a test from the driver BSON Corpus. class Spec # The spec description. # # @return [ String ] The spec description. attr_reader :description # The document key of the object to test. # # @return [ String ] The document key. attr_reader :test_key # Instantiate the new spec. # # @example Create the spec. # Spec.new(file) # # @param [ String ] file The name of the json file. def initialize(file) @spec = ::JSON.parse(File.read(file)) @valid = @spec['valid'] || [] @invalid = @spec['decodeErrors'] || [] @description = @spec['description'] @test_key = @spec['test_key'] end # Get a list of tests that are expected to pass. # # @example Get the list of valid tests. # spec.valid_tests # # @return [ Array ] The list of valid Tests. def valid_tests @valid_tests ||= @valid.collect do |test| BSON::CorpusLegacy::Test.new(self, test) end end # Get a list of tests that raise exceptions. # # @example Get the list of invalid tests. # spec.invalid_tests # # @return [ Array ] The list of invalid Tests. def invalid_tests @invalid_tests ||= @invalid.collect do |test| BSON::CorpusLegacy::Test.new(self, test) end end # The class of the bson object to test. # # @example Get the class of the object to test. # spec.klass # # @return [ Class ] The object class. def klass @klass ||= BSON.const_get(description) end end # Represents a single BSON Corpus test. class Test # The test description. # # @return [ String ] The test description. attr_reader :description # Name of a field in a valid test case extjson document that should be # checked against the case's string field. # # @return [ String ] The json representation of the object. attr_reader :test_key # Instantiate the new Test. # # @example Create the test. # Test.new(test) # # @param [ Corpus::Spec ] spec The test specification. # @param [ Hash ] test The test specification. def initialize(spec, test) @spec = spec @description = test['description'] @canonical_bson = test['canonical_bson'] @extjson = ::JSON.parse(test['extjson']) if test['extjson'] @bson = test['bson'] @test_key = spec.test_key end # The correct representation of the subject as bson. # # @example Get the correct representation of the subject as bson. # test.correct_bson # # @return [ String ] The correct bson bytes. def correct_bson @correct_bson ||= decode_hex(@canonical_bson || @bson) end # Create a BSON::Document object from the test's bson representation # # @return [ BSON::Document ] The BSON::Document object def document_from_bson bson_bytes = decode_hex(@bson) buffer = BSON::ByteBuffer.new(bson_bytes) BSON::Document.from_bson(buffer) end # Create a BSON::Document object from the test's canonical bson # representation # # @return [ BSON::Document ] The BSON::Document object def document_from_canonical_bson bson_bytes = decode_hex(@canonical_bson) buffer = BSON::ByteBuffer.new(bson_bytes) BSON::Document.from_bson(buffer) end # Given the hex representation of bson, decode it into a Document, # then reencoded it to bson. # # @example Decoded the bson hex representation, then reencode. # test.reencoded_bson # # @return [ String ] The reencoded bson bytes. def reencoded_bson document_from_bson.to_bson.to_s end # Given the hex representation of the canonical bson, decode it into a Document, # then reencoded it to bson. # # @example Decoded the canonical bson hex representation, then reencode. # test.reencoded_canonical_bson # # @return [ String ] The reencoded canonical bson bytes. def reencoded_canonical_bson document_from_canonical_bson.to_bson.to_s end # Whether the canonical bson should be tested. # # @example Determine if the canonical bson should be tested. # test.test_canonical_bson? # # @return [ true, false ] Whether the canonical bson should be tested. def test_canonical_bson? @canonical_bson && (@bson != @canonical_bson) end # The correct representation of the subject as extended json. # # @example Get the correct representation of the subject as extended json. # test.correct_extjson # # @return [ String ] The correct extended json representation. def correct_extjson @canonical_extjson || @extjson end # Whether the extended json should be tested. # # @example Determine if the extended json should be tested. # test.test_extjson? # # @return [ true, false ] Whether the extended json should be tested. def test_extjson? !!@extjson end # Get the extended json representation of the decoded doc from the provided # bson hex representation. # # @example Get the extended json representation of the decoded doc. # test.extjson_from_encoded_bson # # @return [ Hash ] The extended json representation. def extjson_from_bson as_legacy_extended_json(document_from_bson) end # Get the extended json representation of the decoded doc from the provided # canonical bson hex representation. # # @example Get the extended json representation of the canonical decoded doc. # test.extjson_from_canonical_bson # # @return [ Hash ] The extended json representation. def extjson_from_canonical_bson as_legacy_extended_json(document_from_canonical_bson) end # Get the extended json representation of the decoded doc from the provided # extended json representation. (Verifies roundtrip) # # @example Get the extended json representation of the canonical decoded doc. # test.extjson_from_encoded_extjson # # @return [ Hash ] The extended json representation. def extjson_from_encoded_extjson doc = BSON::Document.new(@extjson) as_legacy_extended_json(doc) end private def as_legacy_extended_json(object) result = object.as_extended_json(mode: :legacy) if object.respond_to?(:as_json) old_result = object.as_json unless result == old_result raise "Serializing #{object} to legacy extended json did not match between new and old APIs" end end result end def decode_hex(obj) [ obj ].pack('H*') end end end end bson-ruby-4.15.0/spec/shared/000077500000000000000000000000001423026727100157255ustar00rootroot00000000000000bson-ruby-4.15.0/spec/spec_helper.rb000066400000000000000000000056301423026727100173010ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. CURRENT_PATH = File.expand_path(File.dirname(__FILE__)) DRIVER_COMMON_BSON_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/decimal128/*.json").sort BSON_CORPUS_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/corpus/*.json").sort BSON_CORPUS_LEGACY_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/corpus_legacy/*.json").sort $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "shared", "lib")) $LOAD_PATH.unshift(File.dirname(__FILE__)) $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib")) require "ostruct" require "bson" require "json" require "rspec" require "yaml" require 'support/spec_config' if SpecConfig.instance.active_support? require "active_support/version" if ActiveSupport.version >= Gem::Version.new(7) # ActiveSupport wants us to require ALL of it all of the time. # See: https://github.com/rails/rails/issues/43851, # https://github.com/rails/rails/issues/43889, etc. require 'active_support' end require "active_support/time" require 'bson/active_support' end unless ENV['CI'] || BSON::Environment.jruby? begin require 'byebug' rescue Exception end end begin require 'mrss/lite_constraints' rescue LoadError => exc raise LoadError.new <<~MSG.strip The test suite requires shared tooling to be installed. Please refer to spec/README.md for instructions. #{exc.class}: #{exc} MSG end Dir["./spec/support/**/*.rb"].each { |file| require file } # Alternate IO class that returns a String from #readbyte. # See RUBY-898 for more information on why we need to test this. # Ruby core documentation says IO#readbyte returns a Fixnum, but # OpenSSL::SSL::SSLSocket#readbyte returns a String. class AlternateIO < StringIO # Read a byte from the stream. # # @returns [ String ] A String representation of the next byte. def readbyte super.chr end end RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = [:should, :expect] end # To ensure that calling GC.compact does not produce unexpected behavior, # randomly call GC.compact after a small percentage of tests in the suite. # This behavior is only enabled when the COMPACT environment variable is true. if SpecConfig.instance.compact? config.after do if rand < SpecConfig::COMPACTION_CHANCE GC.compact end end end config.extend Mrss::LiteConstraints end bson-ruby-4.15.0/spec/spec_tests/000077500000000000000000000000001423026727100166335ustar00rootroot00000000000000bson-ruby-4.15.0/spec/spec_tests/common_driver_spec.rb000066400000000000000000000047151423026727100230440ustar00rootroot00000000000000require 'spec_helper' require 'runners/common_driver' describe 'Driver common bson tests' do specs = DRIVER_COMMON_BSON_TESTS.map { |file| BSON::CommonDriver::Spec.new(file) } specs.each do |spec| context(spec.description) do spec.valid_tests.each do |test| context(test.description << ' - ' << test.string) do it 'decodes the subject and displays as the correct string' do expect(test.object.to_s).to eq(test.expected_to_string) end it 'encodes the decoded object correctly (roundtrips)' do expect(test.reencoded_hex).to eq(test.subject.upcase) end it 'creates the correct object from extended json', if: test.from_ext_json? do expect(test.from_json_string).to eq(test.object) end it 'creates the correct extended json document from the decoded object', if: test.to_ext_json? do expect(test.document_as_json).to eq(test.ext_json) end it 'parses the string value to the same value as the decoded document', if: test.from_string? do expect(BSON::Decimal128.new(test.string)).to eq(test.object) end it 'parses the #to_s (match_string) value to the same value as the decoded document', if: test.match_string do expect(BSON::Decimal128.new(test.match_string)).to eq(test.object) end it 'creates the correct object from a non canonical string and then prints to the correct string', if: test.match_string do expect(BSON::Decimal128.new(test.string).to_s).to eq(test.match_string) end it 'can be converted to a native type' do expect(test.native_type_conversion).to be_a(test.native_type) end end end spec.invalid_tests.each do |test| context(test.description << " - " << test.subject ) do let(:error) do ex = nil begin test.parse_invalid_string rescue => e ex = e end ex end let(:valid_errors) do [ BSON::Decimal128::InvalidString, BSON::Decimal128::InvalidRange, BSON::Decimal128::UnrepresentablePrecision, ] end it 'raises an exception when parsing' do expect(error.class).to satisfy { |e| valid_errors.include?(e) } end end end end end end bson-ruby-4.15.0/spec/spec_tests/corpus_legacy_spec.rb000066400000000000000000000050111423026727100230260ustar00rootroot00000000000000require 'spec_helper' require 'runners/corpus_legacy' describe 'Driver BSON Corpus Legacy spec tests' do BSON_CORPUS_LEGACY_TESTS.each do |path| basename = File.basename(path) # All of the tests in the failures subdir are failing apparently #basename = path.sub(/.*corpus-tests\//, '') spec = BSON::CorpusLegacy::Spec.new(path) context("(#{basename}): #{spec.description}") do spec.valid_tests.each do |test| context("VALID CASE: #{test.description}") do it 'roundtrips the given bson correctly' do expect(test.reencoded_bson).to eq(test.correct_bson) end context 'when the canonical bson is roundtripped', if: test.test_canonical_bson? do it 'encodes the canonical bson correctly' do expect(test.reencoded_canonical_bson).to eq(test.correct_bson) end end context 'when the document can be represented as extended json', if: test.test_extjson? do it 'decodes from the given bson, then encodes the document as extended json correctly' do expect(test.extjson_from_bson).to eq(test.correct_extjson) expect(test.extjson_from_bson[test.test_key]).to eq(test.correct_extjson[test.test_key]) end it 'decodes from extended json, then encodes the document as extended json correctly' do expect(test.extjson_from_encoded_extjson).to eq(test.correct_extjson) expect(test.extjson_from_encoded_extjson[test.test_key]).to eq(test.correct_extjson[test.test_key]) end context 'when the canonical bson can be represented as extended json', if: (test.test_canonical_bson? && test.test_extjson?) do it 'encodes the canonical bson correctly as extended json' do expect(test.extjson_from_canonical_bson).to eq(test.correct_extjson) expect(test.extjson_from_canonical_bson[test.test_key]).to eq(test.correct_extjson[test.test_key]) end end end end end spec.invalid_tests.each do |test| context("INVALID CASE: #{test.description}") do let(:error) do begin; test.reencoded_bson; false; rescue => e; e; end end it 'raises an error' do skip 'This test case does not raise and error but should' unless error expect do test.reencoded_bson end.to raise_error(error.class) end end end end end end bson-ruby-4.15.0/spec/spec_tests/corpus_spec.rb000066400000000000000000000075411423026727100215140ustar00rootroot00000000000000require 'spec_helper' require 'runners/corpus' describe 'BSON Corpus spec tests' do BSON_CORPUS_TESTS.each do |path| basename = File.basename(path) # All of the tests in the failures subdir are failing apparently #basename = path.sub(/.*corpus-tests\//, '') spec = BSON::Corpus::Spec.new(path) context("(#{basename}): #{spec.description}") do spec.valid_tests&.each do |test| context("valid: #{test.description}") do let(:decoded_canonical_bson) do BSON::Document.from_bson(BSON::ByteBuffer.new(test.canonical_bson), mode: :bson) end it 'round-trips canonical bson' do decoded_canonical_bson.to_bson.to_s.should == test.canonical_bson end =begin it 'converts bson to canonical extended json' do pending raise NotImplementedError end =end it 'converts bson to canonical extended json' do decoded_canonical_bson.as_extended_json.should == test.canonical_extjson_doc end if test.relaxed_extjson it 'converts bson to relaxed extended json' do decoded_canonical_bson.as_extended_json(mode: :relaxed).should == test.relaxed_extjson_doc end let(:parsed_relaxed_extjson) do BSON::ExtJSON.parse_obj(test.relaxed_extjson_doc, mode: :bson) end let(:round_tripped_relaxed_extjson) do parsed_relaxed_extjson.as_extended_json(mode: :relaxed) end # Relaxed extended json may parse into something other than the # canonical bson. For example, relaxed extjson representation for # a small int64 is a number that would serialize to an int32. # But round-tripping extended json back to extjson should produce # the same representation we started with. it 'round-trips relaxed extended json' do round_tripped_relaxed_extjson.should == test.relaxed_extjson_doc end end if test.degenerate_bson let(:decoded_degenerate_bson) do BSON::Document.from_bson(BSON::ByteBuffer.new(test.degenerate_bson), mode: :relaxed) end it 'round-trips degenerate bson to canonical bson' do decoded_degenerate_bson.to_bson.to_s.should == test.canonical_bson end end let(:parsed_canonical_extjson) do BSON::ExtJSON.parse_obj(test.canonical_extjson_doc, mode: :bson) end unless test.lossy? it 'converts canonical extended json to bson' do parsed_canonical_extjson.to_bson.to_s.should == test.canonical_bson end end end end spec.decode_error_tests&.each do |test| context("decode error: #{test.description}") do let(:decoded_bson) do BSON::Document.from_bson(BSON::ByteBuffer.new(test.bson), mode: :bson) end # Until bson-ruby gets an exception hierarchy, we can only rescue # the basic Exception here. # https://jira.mongodb.org/browse/RUBY-1806 it 'raises an exception' do expect do decoded_bson end.to raise_error(Exception) end end end spec.parse_error_tests&.each do |test| context("parse error: #{test.description}") do let(:parsed_extjson) do BSON::ExtJSON.parse(test.string, mode: :bson) end # Until bson-ruby gets an exception hierarchy, we can only rescue # the basic Exception here. # https://jira.mongodb.org/browse/RUBY-1806 it 'raises an exception' do expect do parsed_extjson end.to raise_error(Exception) end end end end end end bson-ruby-4.15.0/spec/spec_tests/data/000077500000000000000000000000001423026727100175445ustar00rootroot00000000000000bson-ruby-4.15.0/spec/spec_tests/data/corpus/000077500000000000000000000000001423026727100210575ustar00rootroot00000000000000bson-ruby-4.15.0/spec/spec_tests/data/corpus/README.md000066400000000000000000000012031423026727100223320ustar00rootroot00000000000000There are the following deliberate changes made to the corpus tests in Ruby: 1. In double.js, Ruby appears to offer less precision than the spec tests demand: irb(main):001:0> -1.23456789012345677E+18 => -1.2345678901234568e+18 Because of this, -1.23456789012345677E+18 was changed to -1.2345678901234568e+18. The "e" was lowercased as well. Both the precision reduction and the lowercasing of "e" changes are also present in the Python driver, which appears to be affected by the same precision limitation. 2. In datetime.js, the millisecond component of iso8601 serialization of timestamps is always present, even if it is zero. bson-ruby-4.15.0/spec/spec_tests/data/corpus/array.json000066400000000000000000000037461423026727100231020ustar00rootroot00000000000000{ "description": "Array", "bson_type": "0x04", "test_key": "a", "valid": [ { "description": "Empty", "canonical_bson": "0D000000046100050000000000", "canonical_extjson": "{\"a\" : []}" }, { "description": "Single Element Array", "canonical_bson": "140000000461000C0000001030000A0000000000", "canonical_extjson": "{\"a\" : [{\"$numberInt\": \"10\"}]}" }, { "description": "Single Element Array with index set incorrectly to empty string", "degenerate_bson": "130000000461000B00000010000A0000000000", "canonical_bson": "140000000461000C0000001030000A0000000000", "canonical_extjson": "{\"a\" : [{\"$numberInt\": \"10\"}]}" }, { "description": "Single Element Array with index set incorrectly to ab", "degenerate_bson": "150000000461000D000000106162000A0000000000", "canonical_bson": "140000000461000C0000001030000A0000000000", "canonical_extjson": "{\"a\" : [{\"$numberInt\": \"10\"}]}" }, { "description": "Multi Element Array with duplicate indexes", "degenerate_bson": "1b000000046100130000001030000a000000103000140000000000", "canonical_bson": "1b000000046100130000001030000a000000103100140000000000", "canonical_extjson": "{\"a\" : [{\"$numberInt\": \"10\"}, {\"$numberInt\": \"20\"}]}" } ], "decodeErrors": [ { "description": "Array length too long: eats outer terminator", "bson": "140000000461000D0000001030000A0000000000" }, { "description": "Array length too short: leaks terminator", "bson": "140000000461000B0000001030000A0000000000" }, { "description": "Invalid Array: bad string length in field", "bson": "1A00000004666F6F00100000000230000500000062617A000000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/binary.json000066400000000000000000000124411423026727100232400ustar00rootroot00000000000000{ "description": "Binary type", "bson_type": "0x05", "test_key": "x", "valid": [ { "description": "subtype 0x00 (Zero-length)", "canonical_bson": "0D000000057800000000000000", "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"\", \"subType\" : \"00\"}}}" }, { "description": "subtype 0x00 (Zero-length, keys reversed)", "canonical_bson": "0D000000057800000000000000", "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"\", \"subType\" : \"00\"}}}", "degenerate_extjson": "{\"x\" : { \"$binary\" : {\"subType\" : \"00\", \"base64\" : \"\"}}}" }, { "description": "subtype 0x00", "canonical_bson": "0F0000000578000200000000FFFF00", "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"//8=\", \"subType\" : \"00\"}}}" }, { "description": "subtype 0x01", "canonical_bson": "0F0000000578000200000001FFFF00", "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"//8=\", \"subType\" : \"01\"}}}" }, { "description": "subtype 0x02", "canonical_bson": "13000000057800060000000202000000FFFF00", "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"//8=\", \"subType\" : \"02\"}}}" }, { "description": "subtype 0x03", "canonical_bson": "1D000000057800100000000373FFD26444B34C6990E8E7D1DFC035D400", "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"03\"}}}" }, { "description": "subtype 0x04", "canonical_bson": "1D000000057800100000000473FFD26444B34C6990E8E7D1DFC035D400", "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"04\"}}}" }, { "description": "subtype 0x04 UUID", "canonical_bson": "1D000000057800100000000473FFD26444B34C6990E8E7D1DFC035D400", "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"04\"}}}", "degenerate_extjson": "{\"x\" : { \"$uuid\" : \"73ffd264-44b3-4c69-90e8-e7d1dfc035d4\"}}" }, { "description": "subtype 0x05", "canonical_bson": "1D000000057800100000000573FFD26444B34C6990E8E7D1DFC035D400", "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"05\"}}}" }, { "description": "subtype 0x07", "canonical_bson": "1D000000057800100000000773FFD26444B34C6990E8E7D1DFC035D400", "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"07\"}}}" }, { "description": "subtype 0x80", "canonical_bson": "0F0000000578000200000080FFFF00", "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"//8=\", \"subType\" : \"80\"}}}" }, { "description": "$type query operator (conflicts with legacy $binary form with $type field)", "canonical_bson": "1F000000037800170000000224747970650007000000737472696E67000000", "canonical_extjson": "{\"x\" : { \"$type\" : \"string\"}}" }, { "description": "$type query operator (conflicts with legacy $binary form with $type field)", "canonical_bson": "180000000378001000000010247479706500020000000000", "canonical_extjson": "{\"x\" : { \"$type\" : {\"$numberInt\": \"2\"}}}" } ], "decodeErrors": [ { "description": "Length longer than document", "bson": "1D000000057800FF0000000573FFD26444B34C6990E8E7D1DFC035D400" }, { "description": "Negative length", "bson": "0D000000057800FFFFFFFF0000" }, { "description": "subtype 0x02 length too long ", "bson": "13000000057800060000000203000000FFFF00" }, { "description": "subtype 0x02 length too short", "bson": "13000000057800060000000201000000FFFF00" }, { "description": "subtype 0x02 length negative one", "bson": "130000000578000600000002FFFFFFFFFFFF00" } ], "parseErrors": [ { "description": "$uuid wrong type", "string": "{\"x\" : { \"$uuid\" : { \"data\" : \"73ffd264-44b3-4c69-90e8-e7d1dfc035d4\"}}}" }, { "description": "$uuid invalid value--too short", "string": "{\"x\" : { \"$uuid\" : \"73ffd264-44b3-90e8-e7d1dfc035d4\"}}" }, { "description": "$uuid invalid value--too long", "string": "{\"x\" : { \"$uuid\" : \"73ffd264-44b3-4c69-90e8-e7d1dfc035d4-789e4\"}}" }, { "description": "$uuid invalid value--misplaced hyphens", "string": "{\"x\" : { \"$uuid\" : \"73ff-d26444b-34c6-990e8e-7d1dfc035d4\"}}" }, { "description": "$uuid invalid value--too many hyphens", "string": "{\"x\" : { \"$uuid\" : \"----d264-44b3-4--9-90e8-e7d1dfc0----\"}}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/boolean.json000066400000000000000000000012551423026727100233740ustar00rootroot00000000000000{ "description": "Boolean", "bson_type": "0x08", "test_key": "b", "valid": [ { "description": "True", "canonical_bson": "090000000862000100", "canonical_extjson": "{\"b\" : true}" }, { "description": "False", "canonical_bson": "090000000862000000", "canonical_extjson": "{\"b\" : false}" } ], "decodeErrors": [ { "description": "Invalid boolean value of 2", "bson": "090000000862000200" }, { "description": "Invalid boolean value of -1", "bson": "09000000086200FF00" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/code.json000066400000000000000000000046001423026727100226640ustar00rootroot00000000000000{ "description": "Javascript Code", "bson_type": "0x0D", "test_key": "a", "valid": [ { "description": "Empty string", "canonical_bson": "0D0000000D6100010000000000", "canonical_extjson": "{\"a\" : {\"$code\" : \"\"}}" }, { "description": "Single character", "canonical_bson": "0E0000000D610002000000620000", "canonical_extjson": "{\"a\" : {\"$code\" : \"b\"}}" }, { "description": "Multi-character", "canonical_bson": "190000000D61000D0000006162616261626162616261620000", "canonical_extjson": "{\"a\" : {\"$code\" : \"abababababab\"}}" }, { "description": "two-byte UTF-8 (\u00e9)", "canonical_bson": "190000000261000D000000C3A9C3A9C3A9C3A9C3A9C3A90000", "canonical_extjson": "{\"a\" : \"\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\"}" }, { "description": "three-byte UTF-8 (\u2606)", "canonical_bson": "190000000261000D000000E29886E29886E29886E298860000", "canonical_extjson": "{\"a\" : \"\\u2606\\u2606\\u2606\\u2606\"}" }, { "description": "Embedded nulls", "canonical_bson": "190000000261000D0000006162006261620062616261620000", "canonical_extjson": "{\"a\" : \"ab\\u0000bab\\u0000babab\"}" } ], "decodeErrors": [ { "description": "bad code string length: 0 (but no 0x00 either)", "bson": "0C0000000261000000000000" }, { "description": "bad code string length: -1", "bson": "0C000000026100FFFFFFFF00" }, { "description": "bad code string length: eats terminator", "bson": "10000000026100050000006200620000" }, { "description": "bad code string length: longer than rest of document", "bson": "120000000200FFFFFF00666F6F6261720000" }, { "description": "code string is not null-terminated", "bson": "1000000002610004000000616263FF00" }, { "description": "empty code string, but extra null", "bson": "0E00000002610001000000000000" }, { "description": "invalid UTF-8", "bson": "0E00000002610002000000E90000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/code_w_scope.json000066400000000000000000000067741423026727100244210ustar00rootroot00000000000000{ "description": "Javascript Code with Scope", "bson_type": "0x0F", "test_key": "a", "valid": [ { "description": "Empty code string, empty scope", "canonical_bson": "160000000F61000E0000000100000000050000000000", "canonical_extjson": "{\"a\" : {\"$code\" : \"\", \"$scope\" : {}}}" }, { "description": "Non-empty code string, empty scope", "canonical_bson": "1A0000000F610012000000050000006162636400050000000000", "canonical_extjson": "{\"a\" : {\"$code\" : \"abcd\", \"$scope\" : {}}}" }, { "description": "Empty code string, non-empty scope", "canonical_bson": "1D0000000F61001500000001000000000C000000107800010000000000", "canonical_extjson": "{\"a\" : {\"$code\" : \"\", \"$scope\" : {\"x\" : {\"$numberInt\": \"1\"}}}}" }, { "description": "Non-empty code string and non-empty scope", "canonical_bson": "210000000F6100190000000500000061626364000C000000107800010000000000", "canonical_extjson": "{\"a\" : {\"$code\" : \"abcd\", \"$scope\" : {\"x\" : {\"$numberInt\": \"1\"}}}}" }, { "description": "Unicode and embedded null in code string, empty scope", "canonical_bson": "1A0000000F61001200000005000000C3A9006400050000000000", "canonical_extjson": "{\"a\" : {\"$code\" : \"\\u00e9\\u0000d\", \"$scope\" : {}}}" } ], "decodeErrors": [ { "description": "field length zero", "bson": "280000000F6100000000000500000061626364001300000010780001000000107900010000000000" }, { "description": "field length negative", "bson": "280000000F6100FFFFFFFF0500000061626364001300000010780001000000107900010000000000" }, { "description": "field length too short (less than minimum size)", "bson": "160000000F61000D0000000100000000050000000000" }, { "description": "field length too short (truncates scope)", "bson": "280000000F61001F0000000500000061626364001300000010780001000000107900010000000000" }, { "description": "field length too long (clips outer doc)", "bson": "280000000F6100210000000500000061626364001300000010780001000000107900010000000000" }, { "description": "field length too long (longer than outer doc)", "bson": "280000000F6100FF0000000500000061626364001300000010780001000000107900010000000000" }, { "description": "bad code string: length too short", "bson": "280000000F6100200000000400000061626364001300000010780001000000107900010000000000" }, { "description": "bad code string: length too long (clips scope)", "bson": "280000000F6100200000000600000061626364001300000010780001000000107900010000000000" }, { "description": "bad code string: negative length", "bson": "280000000F610020000000FFFFFFFF61626364001300000010780001000000107900010000000000" }, { "description": "bad code string: length longer than field", "bson": "280000000F610020000000FF00000061626364001300000010780001000000107900010000000000" }, { "description": "bad scope doc (field has bad string length)", "bson": "1C0000000F001500000001000000000C000000020000000000000000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/datetime.json000066400000000000000000000032561423026727100235540ustar00rootroot00000000000000{ "description": "DateTime", "bson_type": "0x09", "test_key": "a", "valid": [ { "description": "epoch", "canonical_bson": "10000000096100000000000000000000", "relaxed_extjson": "{\"a\" : {\"$date\" : \"1970-01-01T00:00:00Z\"}}", "canonical_extjson": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"0\"}}}" }, { "description": "positive ms", "canonical_bson": "10000000096100C5D8D6CC3B01000000", "relaxed_extjson": "{\"a\" : {\"$date\" : \"2012-12-24T12:15:30.501Z\"}}", "canonical_extjson": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"1356351330501\"}}}" }, { "description": "negative", "canonical_bson": "10000000096100C33CE7B9BDFFFFFF00", "relaxed_extjson": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"-284643869501\"}}}", "canonical_extjson": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"-284643869501\"}}}" }, { "description" : "Y10K", "canonical_bson" : "1000000009610000DC1FD277E6000000", "canonical_extjson" : "{\"a\":{\"$date\":{\"$numberLong\":\"253402300800000\"}}}" }, { "description": "leading zero ms", "canonical_bson": "10000000096100D1D6D6CC3B01000000", "relaxed_extjson": "{\"a\" : {\"$date\" : \"2012-12-24T12:15:30.001Z\"}}", "canonical_extjson": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"1356351330001\"}}}" } ], "decodeErrors": [ { "description": "datetime field truncated", "bson": "0C0000000961001234567800" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/dbpointer.json000066400000000000000000000054031423026727100237420ustar00rootroot00000000000000{ "description": "DBPointer type (deprecated)", "bson_type": "0x0C", "deprecated": true, "test_key": "a", "valid": [ { "description": "DBpointer", "canonical_bson": "1A0000000C610002000000620056E1FC72E0C917E9C471416100", "canonical_extjson": "{\"a\": {\"$dbPointer\": {\"$ref\": \"b\", \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}}}}", "converted_bson": "2a00000003610022000000022472656600020000006200072469640056e1fc72e0c917e9c47141610000", "converted_extjson": "{\"a\": {\"$ref\": \"b\", \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}}}" }, { "description": "DBpointer with opposite key order", "canonical_bson": "1A0000000C610002000000620056E1FC72E0C917E9C471416100", "canonical_extjson": "{\"a\": {\"$dbPointer\": {\"$ref\": \"b\", \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}}}}", "degenerate_extjson": "{\"a\": {\"$dbPointer\": {\"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}, \"$ref\": \"b\"}}}", "converted_bson": "2a00000003610022000000022472656600020000006200072469640056e1fc72e0c917e9c47141610000", "converted_extjson": "{\"a\": {\"$ref\": \"b\", \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}}}" }, { "description": "With two-byte UTF-8", "canonical_bson": "1B0000000C610003000000C3A90056E1FC72E0C917E9C471416100", "canonical_extjson": "{\"a\": {\"$dbPointer\": {\"$ref\": \"é\", \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}}}}", "converted_bson": "2B0000000361002300000002247265660003000000C3A900072469640056E1FC72E0C917E9C47141610000", "converted_extjson": "{\"a\": {\"$ref\": \"é\", \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}}}" } ], "decodeErrors": [ { "description": "String with negative length", "bson": "1A0000000C6100FFFFFFFF620056E1FC72E0C917E9C471416100" }, { "description": "String with zero length", "bson": "1A0000000C610000000000620056E1FC72E0C917E9C471416100" }, { "description": "String not null terminated", "bson": "1A0000000C610002000000626256E1FC72E0C917E9C471416100" }, { "description": "short OID (less than minimum length for field)", "bson": "160000000C61000300000061620056E1FC72E0C91700" }, { "description": "short OID (greater than minimum, but truncated)", "bson": "1A0000000C61000300000061620056E1FC72E0C917E9C4716100" }, { "description": "String with bad UTF-8", "bson": "1A0000000C610002000000E90056E1FC72E0C917E9C471416100" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/dbref.json000066400000000000000000000067661423026727100230530ustar00rootroot00000000000000{ "description": "Document type (DBRef sub-documents)", "bson_type": "0x03", "valid": [ { "description": "DBRef", "canonical_bson": "37000000036462726566002b0000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e0000", "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}}}" }, { "description": "DBRef with database", "canonical_bson": "4300000003646272656600370000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e0224646200030000006462000000", "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}, \"$db\": \"db\"}}" }, { "description": "DBRef with database and additional fields", "canonical_bson": "48000000036462726566003c0000000224726566000b000000636f6c6c656374696f6e0010246964002a00000002246462000300000064620002666f6f0004000000626172000000", "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\", \"$id\": {\"$numberInt\": \"42\"}, \"$db\": \"db\", \"foo\": \"bar\"}}" }, { "description": "DBRef with additional fields", "canonical_bson": "4400000003646272656600380000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e02666f6f0004000000626172000000", "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}, \"foo\": \"bar\"}}" }, { "description": "Document with key names similar to those of a DBRef", "canonical_bson": "3e0000000224726566000c0000006e6f742d612d646272656600072469640058921b3e6e32ab156a22b59e022462616e616e6100050000007065656c0000", "canonical_extjson": "{\"$ref\": \"not-a-dbref\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}, \"$banana\": \"peel\"}" }, { "description": "DBRef with additional dollar-prefixed and dotted fields", "canonical_bson": "48000000036462726566003c0000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e10612e62000100000010246300010000000000", "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}, \"a.b\": {\"$numberInt\": \"1\"}, \"$c\": {\"$numberInt\": \"1\"}}}" }, { "description": "Sub-document resembles DBRef but $id is missing", "canonical_bson": "26000000036462726566001a0000000224726566000b000000636f6c6c656374696f6e000000", "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\"}}" }, { "description": "Sub-document resembles DBRef but $ref is not a string", "canonical_bson": "2c000000036462726566002000000010247265660001000000072469640058921b3e6e32ab156a22b59e0000", "canonical_extjson": "{\"dbref\": {\"$ref\": {\"$numberInt\": \"1\"}, \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}}}" }, { "description": "Sub-document resembles DBRef but $db is not a string", "canonical_bson": "4000000003646272656600340000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e1024646200010000000000", "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}, \"$db\": {\"$numberInt\": \"1\"}}}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/decimal128-1.json000066400000000000000000000431051423026727100237440ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "valid": [ { "description": "Special - Canonical NaN", "canonical_bson": "180000001364000000000000000000000000000000007C00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}" }, { "description": "Special - Negative NaN", "canonical_bson": "18000000136400000000000000000000000000000000FC00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}", "lossy": true }, { "description": "Special - Negative NaN", "canonical_bson": "18000000136400000000000000000000000000000000FC00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-NaN\"}}", "lossy": true }, { "description": "Special - Canonical SNaN", "canonical_bson": "180000001364000000000000000000000000000000007E00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}", "lossy": true }, { "description": "Special - Negative SNaN", "canonical_bson": "18000000136400000000000000000000000000000000FE00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}", "lossy": true }, { "description": "Special - NaN with a payload", "canonical_bson": "180000001364001200000000000000000000000000007E00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}", "lossy": true }, { "description": "Special - Canonical Positive Infinity", "canonical_bson": "180000001364000000000000000000000000000000007800", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" }, { "description": "Special - Canonical Negative Infinity", "canonical_bson": "18000000136400000000000000000000000000000000F800", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" }, { "description": "Special - Invalid representation treated as 0", "canonical_bson": "180000001364000000000000000000000000000000106C00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}", "lossy": true }, { "description": "Special - Invalid representation treated as -0", "canonical_bson": "18000000136400DCBA9876543210DEADBEEF00000010EC00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}", "lossy": true }, { "description": "Special - Invalid representation treated as 0E3", "canonical_bson": "18000000136400FFFFFFFFFFFFFFFFFFFFFFFFFFFF116C00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}", "lossy": true }, { "description": "Regular - Adjusted Exponent Limit", "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CF22F00", "canonical_extjson": "{\"d\": { \"$numberDecimal\": \"0.000001234567890123456789012345678901234\" }}" }, { "description": "Regular - Smallest", "canonical_bson": "18000000136400D204000000000000000000000000343000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.001234\"}}" }, { "description": "Regular - Smallest with Trailing Zeros", "canonical_bson": "1800000013640040EF5A07000000000000000000002A3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00123400000\"}}" }, { "description": "Regular - 0.1", "canonical_bson": "1800000013640001000000000000000000000000003E3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1\"}}" }, { "description": "Regular - 0.1234567890123456789012345678901234", "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CFC2F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1234567890123456789012345678901234\"}}" }, { "description": "Regular - 0", "canonical_bson": "180000001364000000000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "Regular - -0", "canonical_bson": "18000000136400000000000000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" }, { "description": "Regular - -0.0", "canonical_bson": "1800000013640000000000000000000000000000003EB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0\"}}" }, { "description": "Regular - 2", "canonical_bson": "180000001364000200000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2\"}}" }, { "description": "Regular - 2.000", "canonical_bson": "18000000136400D0070000000000000000000000003A3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2.000\"}}" }, { "description": "Regular - Largest", "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1234567890123456789012345678901234\"}}" }, { "description": "Scientific - Tiniest", "canonical_bson": "18000000136400FFFFFFFF638E8D37C087ADBE09ED010000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"9.999999999999999999999999999999999E-6143\"}}" }, { "description": "Scientific - Tiny", "canonical_bson": "180000001364000100000000000000000000000000000000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}" }, { "description": "Scientific - Negative Tiny", "canonical_bson": "180000001364000100000000000000000000000000008000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6176\"}}" }, { "description": "Scientific - Adjusted Exponent Limit", "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CF02F00", "canonical_extjson": "{\"d\": { \"$numberDecimal\": \"1.234567890123456789012345678901234E-7\" }}" }, { "description": "Scientific - Fractional", "canonical_bson": "1800000013640064000000000000000000000000002CB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.00E-8\"}}" }, { "description": "Scientific - 0 with Exponent", "canonical_bson": "180000001364000000000000000000000000000000205F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6000\"}}" }, { "description": "Scientific - 0 with Negative Exponent", "canonical_bson": "1800000013640000000000000000000000000000007A2B00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-611\"}}" }, { "description": "Scientific - No Decimal with Signed Exponent", "canonical_bson": "180000001364000100000000000000000000000000463000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+3\"}}" }, { "description": "Scientific - Trailing Zero", "canonical_bson": "180000001364001A04000000000000000000000000423000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.050E+4\"}}" }, { "description": "Scientific - With Decimal", "canonical_bson": "180000001364006900000000000000000000000000423000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.05E+3\"}}" }, { "description": "Scientific - Full", "canonical_bson": "18000000136400FFFFFFFFFFFFFFFFFFFFFFFFFFFF403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"5192296858534827628530496329220095\"}}" }, { "description": "Scientific - Large", "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}" }, { "description": "Scientific - Largest", "canonical_bson": "18000000136400FFFFFFFF638E8D37C087ADBE09EDFF5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"9.999999999999999999999999999999999E+6144\"}}" }, { "description": "Non-Canonical Parsing - Exponent Normalization", "canonical_bson": "1800000013640064000000000000000000000000002CB000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-100E-10\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.00E-8\"}}" }, { "description": "Non-Canonical Parsing - Unsigned Positive Exponent", "canonical_bson": "180000001364000100000000000000000000000000463000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+3\"}}" }, { "description": "Non-Canonical Parsing - Lowercase Exponent Identifier", "canonical_bson": "180000001364000100000000000000000000000000463000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1e+3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+3\"}}" }, { "description": "Non-Canonical Parsing - Long Significand with Exponent", "canonical_bson": "1800000013640079D9E0F9763ADA429D0200000000583000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12345689012345789012345E+12\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.2345689012345789012345E+34\"}}" }, { "description": "Non-Canonical Parsing - Positive Sign", "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+1234567890123456789012345678901234\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1234567890123456789012345678901234\"}}" }, { "description": "Non-Canonical Parsing - Long Decimal String", "canonical_bson": "180000001364000100000000000000000000000000722800", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \".000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-999\"}}" }, { "description": "Non-Canonical Parsing - nan", "canonical_bson": "180000001364000000000000000000000000000000007C00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"nan\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}" }, { "description": "Non-Canonical Parsing - nAn", "canonical_bson": "180000001364000000000000000000000000000000007C00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"nAn\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}" }, { "description": "Non-Canonical Parsing - +infinity", "canonical_bson": "180000001364000000000000000000000000000000007800", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+infinity\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" }, { "description": "Non-Canonical Parsing - infinity", "canonical_bson": "180000001364000000000000000000000000000000007800", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"infinity\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" }, { "description": "Non-Canonical Parsing - infiniTY", "canonical_bson": "180000001364000000000000000000000000000000007800", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"infiniTY\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" }, { "description": "Non-Canonical Parsing - inf", "canonical_bson": "180000001364000000000000000000000000000000007800", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"inf\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" }, { "description": "Non-Canonical Parsing - inF", "canonical_bson": "180000001364000000000000000000000000000000007800", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"inF\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" }, { "description": "Non-Canonical Parsing - -infinity", "canonical_bson": "18000000136400000000000000000000000000000000F800", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-infinity\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" }, { "description": "Non-Canonical Parsing - -infiniTy", "canonical_bson": "18000000136400000000000000000000000000000000F800", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-infiniTy\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" }, { "description": "Non-Canonical Parsing - -Inf", "canonical_bson": "18000000136400000000000000000000000000000000F800", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" }, { "description": "Non-Canonical Parsing - -inf", "canonical_bson": "18000000136400000000000000000000000000000000F800", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-inf\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" }, { "description": "Non-Canonical Parsing - -inF", "canonical_bson": "18000000136400000000000000000000000000000000F800", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-inF\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" }, { "description": "Rounded Subnormal number", "canonical_bson": "180000001364000100000000000000000000000000000000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10E-6177\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}" }, { "description": "Clamped", "canonical_bson": "180000001364000a00000000000000000000000000fe5f00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E6112\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+6112\"}}" }, { "description": "Exact rounding", "canonical_bson": "18000000136400000000000a5bc138938d44c64d31cc3700", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+999\"}}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/decimal128-2.json000066400000000000000000001136001423026727100237430ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "valid": [ { "description": "[decq021] Normality", "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3C40B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1234567890123456789012345678901234\"}}" }, { "description": "[decq823] values around [u]int32 edges (zeros done earlier)", "canonical_bson": "18000000136400010000800000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-2147483649\"}}" }, { "description": "[decq822] values around [u]int32 edges (zeros done earlier)", "canonical_bson": "18000000136400000000800000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-2147483648\"}}" }, { "description": "[decq821] values around [u]int32 edges (zeros done earlier)", "canonical_bson": "18000000136400FFFFFF7F0000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-2147483647\"}}" }, { "description": "[decq820] values around [u]int32 edges (zeros done earlier)", "canonical_bson": "18000000136400FEFFFF7F0000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-2147483646\"}}" }, { "description": "[decq152] fold-downs (more below)", "canonical_bson": "18000000136400393000000000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-12345\"}}" }, { "description": "[decq154] fold-downs (more below)", "canonical_bson": "18000000136400D20400000000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1234\"}}" }, { "description": "[decq006] derivative canonical plain strings", "canonical_bson": "18000000136400EE0200000000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-750\"}}" }, { "description": "[decq164] fold-downs (more below)", "canonical_bson": "1800000013640039300000000000000000000000003CB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-123.45\"}}" }, { "description": "[decq156] fold-downs (more below)", "canonical_bson": "180000001364007B0000000000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-123\"}}" }, { "description": "[decq008] derivative canonical plain strings", "canonical_bson": "18000000136400EE020000000000000000000000003EB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-75.0\"}}" }, { "description": "[decq158] fold-downs (more below)", "canonical_bson": "180000001364000C0000000000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-12\"}}" }, { "description": "[decq122] Nmax and similar", "canonical_bson": "18000000136400FFFFFFFF638E8D37C087ADBE09EDFFDF00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.999999999999999999999999999999999E+6144\"}}" }, { "description": "[decq002] (mostly derived from the Strawman 4 document and examples)", "canonical_bson": "18000000136400EE020000000000000000000000003CB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-7.50\"}}" }, { "description": "[decq004] derivative canonical plain strings", "canonical_bson": "18000000136400EE0200000000000000000000000042B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-7.50E+3\"}}" }, { "description": "[decq018] derivative canonical plain strings", "canonical_bson": "18000000136400EE020000000000000000000000002EB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-7.50E-7\"}}" }, { "description": "[decq125] Nmax and similar", "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CFEDF00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.234567890123456789012345678901234E+6144\"}}" }, { "description": "[decq131] fold-downs (more below)", "canonical_bson": "18000000136400000000807F1BCF85B27059C8A43CFEDF00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.230000000000000000000000000000000E+6144\"}}" }, { "description": "[decq162] fold-downs (more below)", "canonical_bson": "180000001364007B000000000000000000000000003CB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.23\"}}" }, { "description": "[decq176] Nmin and below", "canonical_bson": "18000000136400010000000A5BC138938D44C64D31008000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.000000000000000000000000000000001E-6143\"}}" }, { "description": "[decq174] Nmin and below", "canonical_bson": "18000000136400000000000A5BC138938D44C64D31008000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.000000000000000000000000000000000E-6143\"}}" }, { "description": "[decq133] fold-downs (more below)", "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FEDF00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.000000000000000000000000000000000E+6144\"}}" }, { "description": "[decq160] fold-downs (more below)", "canonical_bson": "18000000136400010000000000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1\"}}" }, { "description": "[decq172] Nmin and below", "canonical_bson": "180000001364000100000000000000000000000000428000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6143\"}}" }, { "description": "[decq010] derivative canonical plain strings", "canonical_bson": "18000000136400EE020000000000000000000000003AB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.750\"}}" }, { "description": "[decq012] derivative canonical plain strings", "canonical_bson": "18000000136400EE0200000000000000000000000038B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0750\"}}" }, { "description": "[decq014] derivative canonical plain strings", "canonical_bson": "18000000136400EE0200000000000000000000000034B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000750\"}}" }, { "description": "[decq016] derivative canonical plain strings", "canonical_bson": "18000000136400EE0200000000000000000000000030B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000750\"}}" }, { "description": "[decq404] zeros", "canonical_bson": "180000001364000000000000000000000000000000000000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6176\"}}" }, { "description": "[decq424] negative zeros", "canonical_bson": "180000001364000000000000000000000000000000008000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6176\"}}" }, { "description": "[decq407] zeros", "canonical_bson": "1800000013640000000000000000000000000000003C3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}" }, { "description": "[decq427] negative zeros", "canonical_bson": "1800000013640000000000000000000000000000003CB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}" }, { "description": "[decq409] zeros", "canonical_bson": "180000001364000000000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[decq428] negative zeros", "canonical_bson": "18000000136400000000000000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" }, { "description": "[decq700] Selected DPD codes", "canonical_bson": "180000001364000000000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[decq406] zeros", "canonical_bson": "1800000013640000000000000000000000000000003C3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}" }, { "description": "[decq426] negative zeros", "canonical_bson": "1800000013640000000000000000000000000000003CB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}" }, { "description": "[decq410] zeros", "canonical_bson": "180000001364000000000000000000000000000000463000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}" }, { "description": "[decq431] negative zeros", "canonical_bson": "18000000136400000000000000000000000000000046B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+3\"}}" }, { "description": "[decq419] clamped zeros...", "canonical_bson": "180000001364000000000000000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6111\"}}" }, { "description": "[decq432] negative zeros", "canonical_bson": "180000001364000000000000000000000000000000FEDF00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6111\"}}" }, { "description": "[decq405] zeros", "canonical_bson": "180000001364000000000000000000000000000000000000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6176\"}}" }, { "description": "[decq425] negative zeros", "canonical_bson": "180000001364000000000000000000000000000000008000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6176\"}}" }, { "description": "[decq508] Specials", "canonical_bson": "180000001364000000000000000000000000000000007800", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" }, { "description": "[decq528] Specials", "canonical_bson": "18000000136400000000000000000000000000000000F800", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" }, { "description": "[decq541] Specials", "canonical_bson": "180000001364000000000000000000000000000000007C00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}" }, { "description": "[decq074] Nmin and below", "canonical_bson": "18000000136400000000000A5BC138938D44C64D31000000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E-6143\"}}" }, { "description": "[decq602] fold-down full sequence", "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}" }, { "description": "[decq604] fold-down full sequence", "canonical_bson": "180000001364000000000081EFAC855B416D2DEE04FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000000E+6143\"}}" }, { "description": "[decq606] fold-down full sequence", "canonical_bson": "1800000013640000000080264B91C02220BE377E00FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000000000E+6142\"}}" }, { "description": "[decq608] fold-down full sequence", "canonical_bson": "1800000013640000000040EAED7446D09C2C9F0C00FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000E+6141\"}}" }, { "description": "[decq610] fold-down full sequence", "canonical_bson": "18000000136400000000A0CA17726DAE0F1E430100FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000E+6140\"}}" }, { "description": "[decq612] fold-down full sequence", "canonical_bson": "18000000136400000000106102253E5ECE4F200000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000000E+6139\"}}" }, { "description": "[decq614] fold-down full sequence", "canonical_bson": "18000000136400000000E83C80D09F3C2E3B030000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000E+6138\"}}" }, { "description": "[decq616] fold-down full sequence", "canonical_bson": "18000000136400000000E4D20CC8DCD2B752000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000E+6137\"}}" }, { "description": "[decq618] fold-down full sequence", "canonical_bson": "180000001364000000004A48011416954508000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000E+6136\"}}" }, { "description": "[decq620] fold-down full sequence", "canonical_bson": "18000000136400000000A1EDCCCE1BC2D300000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000E+6135\"}}" }, { "description": "[decq622] fold-down full sequence", "canonical_bson": "18000000136400000080F64AE1C7022D1500000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000E+6134\"}}" }, { "description": "[decq624] fold-down full sequence", "canonical_bson": "18000000136400000040B2BAC9E0191E0200000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000E+6133\"}}" }, { "description": "[decq626] fold-down full sequence", "canonical_bson": "180000001364000000A0DEC5ADC935360000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000E+6132\"}}" }, { "description": "[decq628] fold-down full sequence", "canonical_bson": "18000000136400000010632D5EC76B050000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000E+6131\"}}" }, { "description": "[decq630] fold-down full sequence", "canonical_bson": "180000001364000000E8890423C78A000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000E+6130\"}}" }, { "description": "[decq632] fold-down full sequence", "canonical_bson": "18000000136400000064A7B3B6E00D000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000E+6129\"}}" }, { "description": "[decq634] fold-down full sequence", "canonical_bson": "1800000013640000008A5D78456301000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000E+6128\"}}" }, { "description": "[decq636] fold-down full sequence", "canonical_bson": "180000001364000000C16FF2862300000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000E+6127\"}}" }, { "description": "[decq638] fold-down full sequence", "canonical_bson": "180000001364000080C6A47E8D0300000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000E+6126\"}}" }, { "description": "[decq640] fold-down full sequence", "canonical_bson": "1800000013640000407A10F35A0000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000E+6125\"}}" }, { "description": "[decq642] fold-down full sequence", "canonical_bson": "1800000013640000A0724E18090000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000E+6124\"}}" }, { "description": "[decq644] fold-down full sequence", "canonical_bson": "180000001364000010A5D4E8000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000E+6123\"}}" }, { "description": "[decq646] fold-down full sequence", "canonical_bson": "1800000013640000E8764817000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000E+6122\"}}" }, { "description": "[decq648] fold-down full sequence", "canonical_bson": "1800000013640000E40B5402000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000E+6121\"}}" }, { "description": "[decq650] fold-down full sequence", "canonical_bson": "1800000013640000CA9A3B00000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000E+6120\"}}" }, { "description": "[decq652] fold-down full sequence", "canonical_bson": "1800000013640000E1F50500000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000E+6119\"}}" }, { "description": "[decq654] fold-down full sequence", "canonical_bson": "180000001364008096980000000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000E+6118\"}}" }, { "description": "[decq656] fold-down full sequence", "canonical_bson": "1800000013640040420F0000000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000E+6117\"}}" }, { "description": "[decq658] fold-down full sequence", "canonical_bson": "18000000136400A086010000000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000E+6116\"}}" }, { "description": "[decq660] fold-down full sequence", "canonical_bson": "180000001364001027000000000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000E+6115\"}}" }, { "description": "[decq662] fold-down full sequence", "canonical_bson": "18000000136400E803000000000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000E+6114\"}}" }, { "description": "[decq664] fold-down full sequence", "canonical_bson": "180000001364006400000000000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+6113\"}}" }, { "description": "[decq666] fold-down full sequence", "canonical_bson": "180000001364000A00000000000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+6112\"}}" }, { "description": "[decq060] fold-downs (more below)", "canonical_bson": "180000001364000100000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1\"}}" }, { "description": "[decq670] fold-down full sequence", "canonical_bson": "180000001364000100000000000000000000000000FC5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6110\"}}" }, { "description": "[decq668] fold-down full sequence", "canonical_bson": "180000001364000100000000000000000000000000FE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6111\"}}" }, { "description": "[decq072] Nmin and below", "canonical_bson": "180000001364000100000000000000000000000000420000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6143\"}}" }, { "description": "[decq076] Nmin and below", "canonical_bson": "18000000136400010000000A5BC138938D44C64D31000000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000001E-6143\"}}" }, { "description": "[decq036] fold-downs (more below)", "canonical_bson": "18000000136400000000807F1BCF85B27059C8A43CFE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.230000000000000000000000000000000E+6144\"}}" }, { "description": "[decq062] fold-downs (more below)", "canonical_bson": "180000001364007B000000000000000000000000003C3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.23\"}}" }, { "description": "[decq034] Nmax and similar", "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CFE5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.234567890123456789012345678901234E+6144\"}}" }, { "description": "[decq441] exponent lengths", "canonical_bson": "180000001364000700000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7\"}}" }, { "description": "[decq449] exponent lengths", "canonical_bson": "1800000013640007000000000000000000000000001E5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+5999\"}}" }, { "description": "[decq447] exponent lengths", "canonical_bson": "1800000013640007000000000000000000000000000E3800", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+999\"}}" }, { "description": "[decq445] exponent lengths", "canonical_bson": "180000001364000700000000000000000000000000063100", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+99\"}}" }, { "description": "[decq443] exponent lengths", "canonical_bson": "180000001364000700000000000000000000000000523000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+9\"}}" }, { "description": "[decq842] VG testcase", "canonical_bson": "180000001364000000FED83F4E7C9FE4E269E38A5BCD1700", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7.049000000000010795488000000000000E-3097\"}}" }, { "description": "[decq841] VG testcase", "canonical_bson": "180000001364000000203B9DB5056F000000000000002400", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"8.000000000000000000E-1550\"}}" }, { "description": "[decq840] VG testcase", "canonical_bson": "180000001364003C17258419D710C42F0000000000002400", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"8.81125000000001349436E-1548\"}}" }, { "description": "[decq701] Selected DPD codes", "canonical_bson": "180000001364000900000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"9\"}}" }, { "description": "[decq032] Nmax and similar", "canonical_bson": "18000000136400FFFFFFFF638E8D37C087ADBE09EDFF5F00", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"9.999999999999999999999999999999999E+6144\"}}" }, { "description": "[decq702] Selected DPD codes", "canonical_bson": "180000001364000A00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10\"}}" }, { "description": "[decq057] fold-downs (more below)", "canonical_bson": "180000001364000C00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12\"}}" }, { "description": "[decq703] Selected DPD codes", "canonical_bson": "180000001364001300000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"19\"}}" }, { "description": "[decq704] Selected DPD codes", "canonical_bson": "180000001364001400000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"20\"}}" }, { "description": "[decq705] Selected DPD codes", "canonical_bson": "180000001364001D00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"29\"}}" }, { "description": "[decq706] Selected DPD codes", "canonical_bson": "180000001364001E00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"30\"}}" }, { "description": "[decq707] Selected DPD codes", "canonical_bson": "180000001364002700000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"39\"}}" }, { "description": "[decq708] Selected DPD codes", "canonical_bson": "180000001364002800000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"40\"}}" }, { "description": "[decq709] Selected DPD codes", "canonical_bson": "180000001364003100000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"49\"}}" }, { "description": "[decq710] Selected DPD codes", "canonical_bson": "180000001364003200000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"50\"}}" }, { "description": "[decq711] Selected DPD codes", "canonical_bson": "180000001364003B00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"59\"}}" }, { "description": "[decq712] Selected DPD codes", "canonical_bson": "180000001364003C00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"60\"}}" }, { "description": "[decq713] Selected DPD codes", "canonical_bson": "180000001364004500000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"69\"}}" }, { "description": "[decq714] Selected DPD codes", "canonical_bson": "180000001364004600000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"70\"}}" }, { "description": "[decq715] Selected DPD codes", "canonical_bson": "180000001364004700000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"71\"}}" }, { "description": "[decq716] Selected DPD codes", "canonical_bson": "180000001364004800000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"72\"}}" }, { "description": "[decq717] Selected DPD codes", "canonical_bson": "180000001364004900000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"73\"}}" }, { "description": "[decq718] Selected DPD codes", "canonical_bson": "180000001364004A00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"74\"}}" }, { "description": "[decq719] Selected DPD codes", "canonical_bson": "180000001364004B00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"75\"}}" }, { "description": "[decq720] Selected DPD codes", "canonical_bson": "180000001364004C00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"76\"}}" }, { "description": "[decq721] Selected DPD codes", "canonical_bson": "180000001364004D00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"77\"}}" }, { "description": "[decq722] Selected DPD codes", "canonical_bson": "180000001364004E00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"78\"}}" }, { "description": "[decq723] Selected DPD codes", "canonical_bson": "180000001364004F00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"79\"}}" }, { "description": "[decq056] fold-downs (more below)", "canonical_bson": "180000001364007B00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"123\"}}" }, { "description": "[decq064] fold-downs (more below)", "canonical_bson": "1800000013640039300000000000000000000000003C3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"123.45\"}}" }, { "description": "[decq732] Selected DPD codes", "canonical_bson": "180000001364000802000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"520\"}}" }, { "description": "[decq733] Selected DPD codes", "canonical_bson": "180000001364000902000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"521\"}}" }, { "description": "[decq740] DPD: one of each of the huffman groups", "canonical_bson": "180000001364000903000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"777\"}}" }, { "description": "[decq741] DPD: one of each of the huffman groups", "canonical_bson": "180000001364000A03000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"778\"}}" }, { "description": "[decq742] DPD: one of each of the huffman groups", "canonical_bson": "180000001364001303000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"787\"}}" }, { "description": "[decq746] DPD: one of each of the huffman groups", "canonical_bson": "180000001364001F03000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"799\"}}" }, { "description": "[decq743] DPD: one of each of the huffman groups", "canonical_bson": "180000001364006D03000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"877\"}}" }, { "description": "[decq753] DPD all-highs cases (includes the 24 redundant codes)", "canonical_bson": "180000001364007803000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"888\"}}" }, { "description": "[decq754] DPD all-highs cases (includes the 24 redundant codes)", "canonical_bson": "180000001364007903000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"889\"}}" }, { "description": "[decq760] DPD all-highs cases (includes the 24 redundant codes)", "canonical_bson": "180000001364008203000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"898\"}}" }, { "description": "[decq764] DPD all-highs cases (includes the 24 redundant codes)", "canonical_bson": "180000001364008303000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"899\"}}" }, { "description": "[decq745] DPD: one of each of the huffman groups", "canonical_bson": "18000000136400D303000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"979\"}}" }, { "description": "[decq770] DPD all-highs cases (includes the 24 redundant codes)", "canonical_bson": "18000000136400DC03000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"988\"}}" }, { "description": "[decq774] DPD all-highs cases (includes the 24 redundant codes)", "canonical_bson": "18000000136400DD03000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"989\"}}" }, { "description": "[decq730] Selected DPD codes", "canonical_bson": "18000000136400E203000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"994\"}}" }, { "description": "[decq731] Selected DPD codes", "canonical_bson": "18000000136400E303000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"995\"}}" }, { "description": "[decq744] DPD: one of each of the huffman groups", "canonical_bson": "18000000136400E503000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"997\"}}" }, { "description": "[decq780] DPD all-highs cases (includes the 24 redundant codes)", "canonical_bson": "18000000136400E603000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"998\"}}" }, { "description": "[decq787] DPD all-highs cases (includes the 24 redundant codes)", "canonical_bson": "18000000136400E703000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"999\"}}" }, { "description": "[decq053] fold-downs (more below)", "canonical_bson": "18000000136400D204000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1234\"}}" }, { "description": "[decq052] fold-downs (more below)", "canonical_bson": "180000001364003930000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12345\"}}" }, { "description": "[decq792] Miscellaneous (testers' queries, etc.)", "canonical_bson": "180000001364003075000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"30000\"}}" }, { "description": "[decq793] Miscellaneous (testers' queries, etc.)", "canonical_bson": "1800000013640090940D0000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"890000\"}}" }, { "description": "[decq824] values around [u]int32 edges (zeros done earlier)", "canonical_bson": "18000000136400FEFFFF7F00000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2147483646\"}}" }, { "description": "[decq825] values around [u]int32 edges (zeros done earlier)", "canonical_bson": "18000000136400FFFFFF7F00000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2147483647\"}}" }, { "description": "[decq826] values around [u]int32 edges (zeros done earlier)", "canonical_bson": "180000001364000000008000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2147483648\"}}" }, { "description": "[decq827] values around [u]int32 edges (zeros done earlier)", "canonical_bson": "180000001364000100008000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2147483649\"}}" }, { "description": "[decq828] values around [u]int32 edges (zeros done earlier)", "canonical_bson": "18000000136400FEFFFFFF00000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"4294967294\"}}" }, { "description": "[decq829] values around [u]int32 edges (zeros done earlier)", "canonical_bson": "18000000136400FFFFFFFF00000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"4294967295\"}}" }, { "description": "[decq830] values around [u]int32 edges (zeros done earlier)", "canonical_bson": "180000001364000000000001000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"4294967296\"}}" }, { "description": "[decq831] values around [u]int32 edges (zeros done earlier)", "canonical_bson": "180000001364000100000001000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"4294967297\"}}" }, { "description": "[decq022] Normality", "canonical_bson": "18000000136400C7711CC7B548F377DC80A131C836403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1111111111111111111111111111111111\"}}" }, { "description": "[decq020] Normality", "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1234567890123456789012345678901234\"}}" }, { "description": "[decq550] Specials", "canonical_bson": "18000000136400FFFFFFFF638E8D37C087ADBE09ED413000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"9999999999999999999999999999999999\"}}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/decimal128-3.json000066400000000000000000002613321423026727100237520ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "valid": [ { "description": "[basx066] strings without E cannot generate E in result", "canonical_bson": "18000000136400185C0ACE0000000000000000000038B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-00345678.5432\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-345678.5432\"}}" }, { "description": "[basx065] strings without E cannot generate E in result", "canonical_bson": "18000000136400185C0ACE0000000000000000000038B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0345678.5432\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-345678.5432\"}}" }, { "description": "[basx064] strings without E cannot generate E in result", "canonical_bson": "18000000136400185C0ACE0000000000000000000038B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-345678.5432\"}}" }, { "description": "[basx041] strings without E cannot generate E in result", "canonical_bson": "180000001364004C0000000000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-76\"}}" }, { "description": "[basx027] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364000F270000000000000000000000003AB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.999\"}}" }, { "description": "[basx026] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364009F230000000000000000000000003AB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.119\"}}" }, { "description": "[basx025] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364008F030000000000000000000000003CB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.11\"}}" }, { "description": "[basx024] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364005B000000000000000000000000003EB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.1\"}}" }, { "description": "[dqbsr531] negatives (Rounded)", "canonical_bson": "1800000013640099761CC7B548F377DC80A131C836FEAF00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.1111111111111111111111111111123450\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.111111111111111111111111111112345\"}}" }, { "description": "[basx022] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364000A000000000000000000000000003EB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.0\"}}" }, { "description": "[basx021] conform to rules and exponent will be in permitted range).", "canonical_bson": "18000000136400010000000000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1\"}}" }, { "description": "[basx601] Zeros", "canonical_bson": "1800000013640000000000000000000000000000002E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000000\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-9\"}}" }, { "description": "[basx622] Zeros", "canonical_bson": "1800000013640000000000000000000000000000002EB000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000000\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-9\"}}" }, { "description": "[basx602] Zeros", "canonical_bson": "180000001364000000000000000000000000000000303000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000000\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-8\"}}" }, { "description": "[basx621] Zeros", "canonical_bson": "18000000136400000000000000000000000000000030B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000000\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-8\"}}" }, { "description": "[basx603] Zeros", "canonical_bson": "180000001364000000000000000000000000000000323000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000000\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}" }, { "description": "[basx620] Zeros", "canonical_bson": "18000000136400000000000000000000000000000032B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000000\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-7\"}}" }, { "description": "[basx604] Zeros", "canonical_bson": "180000001364000000000000000000000000000000343000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}" }, { "description": "[basx619] Zeros", "canonical_bson": "18000000136400000000000000000000000000000034B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000\"}}" }, { "description": "[basx605] Zeros", "canonical_bson": "180000001364000000000000000000000000000000363000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}" }, { "description": "[basx618] Zeros", "canonical_bson": "18000000136400000000000000000000000000000036B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000\"}}" }, { "description": "[basx680] Zeros", "canonical_bson": "180000001364000000000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"000000.\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[basx606] Zeros", "canonical_bson": "180000001364000000000000000000000000000000383000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}" }, { "description": "[basx617] Zeros", "canonical_bson": "18000000136400000000000000000000000000000038B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000\"}}" }, { "description": "[basx681] Zeros", "canonical_bson": "180000001364000000000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"00000.\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[basx686] Zeros", "canonical_bson": "180000001364000000000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+00000.\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[basx687] Zeros", "canonical_bson": "18000000136400000000000000000000000000000040B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-00000.\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" }, { "description": "[basx019] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640000000000000000000000000000003CB000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-00.00\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}" }, { "description": "[basx607] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003A3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000\"}}" }, { "description": "[basx616] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003AB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000\"}}" }, { "description": "[basx682] Zeros", "canonical_bson": "180000001364000000000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0000.\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[basx155] Numbers with E", "canonical_bson": "1800000013640000000000000000000000000000003A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000e+0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000\"}}" }, { "description": "[basx130] Numbers with E", "canonical_bson": "180000001364000000000000000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000E-1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}" }, { "description": "[basx290] some more negative zeros [systematic tests below]", "canonical_bson": "18000000136400000000000000000000000000000038B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000E-1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000\"}}" }, { "description": "[basx131] Numbers with E", "canonical_bson": "180000001364000000000000000000000000000000363000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}" }, { "description": "[basx291] some more negative zeros [systematic tests below]", "canonical_bson": "18000000136400000000000000000000000000000036B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000\"}}" }, { "description": "[basx132] Numbers with E", "canonical_bson": "180000001364000000000000000000000000000000343000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}" }, { "description": "[basx292] some more negative zeros [systematic tests below]", "canonical_bson": "18000000136400000000000000000000000000000034B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000\"}}" }, { "description": "[basx133] Numbers with E", "canonical_bson": "180000001364000000000000000000000000000000323000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000E-4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}" }, { "description": "[basx293] some more negative zeros [systematic tests below]", "canonical_bson": "18000000136400000000000000000000000000000032B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000E-4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-7\"}}" }, { "description": "[basx608] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003C3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}" }, { "description": "[basx615] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003CB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}" }, { "description": "[basx683] Zeros", "canonical_bson": "180000001364000000000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"000.\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[basx630] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}" }, { "description": "[basx670] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}" }, { "description": "[basx631] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}" }, { "description": "[basx671] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000\"}}" }, { "description": "[basx134] Numbers with E", "canonical_bson": "180000001364000000000000000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}" }, { "description": "[basx294] some more negative zeros [systematic tests below]", "canonical_bson": "18000000136400000000000000000000000000000038B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000\"}}" }, { "description": "[basx632] Zeros", "canonical_bson": "180000001364000000000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[basx672] Zeros", "canonical_bson": "180000001364000000000000000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}" }, { "description": "[basx135] Numbers with E", "canonical_bson": "180000001364000000000000000000000000000000363000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}" }, { "description": "[basx295] some more negative zeros [systematic tests below]", "canonical_bson": "18000000136400000000000000000000000000000036B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000\"}}" }, { "description": "[basx633] Zeros", "canonical_bson": "180000001364000000000000000000000000000000423000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+1\"}}" }, { "description": "[basx673] Zeros", "canonical_bson": "180000001364000000000000000000000000000000363000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}" }, { "description": "[basx136] Numbers with E", "canonical_bson": "180000001364000000000000000000000000000000343000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}" }, { "description": "[basx674] Zeros", "canonical_bson": "180000001364000000000000000000000000000000343000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}" }, { "description": "[basx634] Zeros", "canonical_bson": "180000001364000000000000000000000000000000443000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+2\"}}" }, { "description": "[basx137] Numbers with E", "canonical_bson": "180000001364000000000000000000000000000000323000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-5\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}" }, { "description": "[basx635] Zeros", "canonical_bson": "180000001364000000000000000000000000000000463000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+5\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}" }, { "description": "[basx675] Zeros", "canonical_bson": "180000001364000000000000000000000000000000323000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-5\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}" }, { "description": "[basx636] Zeros", "canonical_bson": "180000001364000000000000000000000000000000483000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+6\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+4\"}}" }, { "description": "[basx676] Zeros", "canonical_bson": "180000001364000000000000000000000000000000303000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-6\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-8\"}}" }, { "description": "[basx637] Zeros", "canonical_bson": "1800000013640000000000000000000000000000004A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+7\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+5\"}}" }, { "description": "[basx677] Zeros", "canonical_bson": "1800000013640000000000000000000000000000002E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-7\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-9\"}}" }, { "description": "[basx638] Zeros", "canonical_bson": "1800000013640000000000000000000000000000004C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6\"}}" }, { "description": "[basx678] Zeros", "canonical_bson": "1800000013640000000000000000000000000000002C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-10\"}}" }, { "description": "[basx149] Numbers with E", "canonical_bson": "180000001364000000000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"000E+9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}" }, { "description": "[basx639] Zeros", "canonical_bson": "1800000013640000000000000000000000000000004E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+7\"}}" }, { "description": "[basx679] Zeros", "canonical_bson": "1800000013640000000000000000000000000000002A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-11\"}}" }, { "description": "[basx063] strings without E cannot generate E in result", "canonical_bson": "18000000136400185C0ACE00000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+00345678.5432\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.5432\"}}" }, { "description": "[basx018] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640000000000000000000000000000003EB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0\"}}" }, { "description": "[basx609] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003E3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}" }, { "description": "[basx614] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003EB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0\"}}" }, { "description": "[basx684] Zeros", "canonical_bson": "180000001364000000000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"00.\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[basx640] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}" }, { "description": "[basx660] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}" }, { "description": "[basx641] Zeros", "canonical_bson": "180000001364000000000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[basx661] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}" }, { "description": "[basx296] some more negative zeros [systematic tests below]", "canonical_bson": "1800000013640000000000000000000000000000003AB000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000\"}}" }, { "description": "[basx642] Zeros", "canonical_bson": "180000001364000000000000000000000000000000423000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+1\"}}" }, { "description": "[basx662] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000\"}}" }, { "description": "[basx297] some more negative zeros [systematic tests below]", "canonical_bson": "18000000136400000000000000000000000000000038B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000\"}}" }, { "description": "[basx643] Zeros", "canonical_bson": "180000001364000000000000000000000000000000443000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+2\"}}" }, { "description": "[basx663] Zeros", "canonical_bson": "180000001364000000000000000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}" }, { "description": "[basx644] Zeros", "canonical_bson": "180000001364000000000000000000000000000000463000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}" }, { "description": "[basx664] Zeros", "canonical_bson": "180000001364000000000000000000000000000000363000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}" }, { "description": "[basx645] Zeros", "canonical_bson": "180000001364000000000000000000000000000000483000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+5\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+4\"}}" }, { "description": "[basx665] Zeros", "canonical_bson": "180000001364000000000000000000000000000000343000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-5\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}" }, { "description": "[basx646] Zeros", "canonical_bson": "1800000013640000000000000000000000000000004A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+6\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+5\"}}" }, { "description": "[basx666] Zeros", "canonical_bson": "180000001364000000000000000000000000000000323000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-6\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}" }, { "description": "[basx647] Zeros", "canonical_bson": "1800000013640000000000000000000000000000004C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+7\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6\"}}" }, { "description": "[basx667] Zeros", "canonical_bson": "180000001364000000000000000000000000000000303000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-7\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-8\"}}" }, { "description": "[basx648] Zeros", "canonical_bson": "1800000013640000000000000000000000000000004E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+7\"}}" }, { "description": "[basx668] Zeros", "canonical_bson": "1800000013640000000000000000000000000000002E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-9\"}}" }, { "description": "[basx160] Numbers with E", "canonical_bson": "180000001364000000000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"00E+9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}" }, { "description": "[basx161] Numbers with E", "canonical_bson": "1800000013640000000000000000000000000000002E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"00E-9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-9\"}}" }, { "description": "[basx649] Zeros", "canonical_bson": "180000001364000000000000000000000000000000503000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+8\"}}" }, { "description": "[basx669] Zeros", "canonical_bson": "1800000013640000000000000000000000000000002C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-10\"}}" }, { "description": "[basx062] strings without E cannot generate E in result", "canonical_bson": "18000000136400185C0ACE00000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+0345678.5432\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.5432\"}}" }, { "description": "[basx001] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364000000000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[basx017] conform to rules and exponent will be in permitted range).", "canonical_bson": "18000000136400000000000000000000000000000040B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" }, { "description": "[basx611] Zeros", "canonical_bson": "180000001364000000000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[basx613] Zeros", "canonical_bson": "18000000136400000000000000000000000000000040B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" }, { "description": "[basx685] Zeros", "canonical_bson": "180000001364000000000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[basx688] Zeros", "canonical_bson": "180000001364000000000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+0.\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[basx689] Zeros", "canonical_bson": "18000000136400000000000000000000000000000040B000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" }, { "description": "[basx650] Zeros", "canonical_bson": "180000001364000000000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "[basx651] Zeros", "canonical_bson": "180000001364000000000000000000000000000000423000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+1\"}}" }, { "description": "[basx298] some more negative zeros [systematic tests below]", "canonical_bson": "1800000013640000000000000000000000000000003CB000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}" }, { "description": "[basx652] Zeros", "canonical_bson": "180000001364000000000000000000000000000000443000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+2\"}}" }, { "description": "[basx299] some more negative zeros [systematic tests below]", "canonical_bson": "1800000013640000000000000000000000000000003AB000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000\"}}" }, { "description": "[basx653] Zeros", "canonical_bson": "180000001364000000000000000000000000000000463000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}" }, { "description": "[basx654] Zeros", "canonical_bson": "180000001364000000000000000000000000000000483000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+4\"}}" }, { "description": "[basx655] Zeros", "canonical_bson": "1800000013640000000000000000000000000000004A3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+5\"}}" }, { "description": "[basx656] Zeros", "canonical_bson": "1800000013640000000000000000000000000000004C3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6\"}}" }, { "description": "[basx657] Zeros", "canonical_bson": "1800000013640000000000000000000000000000004E3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+7\"}}" }, { "description": "[basx658] Zeros", "canonical_bson": "180000001364000000000000000000000000000000503000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+8\"}}" }, { "description": "[basx138] Numbers with E", "canonical_bson": "180000001364000000000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+0E+9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}" }, { "description": "[basx139] Numbers with E", "canonical_bson": "18000000136400000000000000000000000000000052B000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+9\"}}" }, { "description": "[basx144] Numbers with E", "canonical_bson": "180000001364000000000000000000000000000000523000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}" }, { "description": "[basx154] Numbers with E", "canonical_bson": "180000001364000000000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}" }, { "description": "[basx659] Zeros", "canonical_bson": "180000001364000000000000000000000000000000523000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}" }, { "description": "[basx042] strings without E cannot generate E in result", "canonical_bson": "18000000136400FC040000000000000000000000003C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+12.76\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.76\"}}" }, { "description": "[basx143] Numbers with E", "canonical_bson": "180000001364000100000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+1E+009\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" }, { "description": "[basx061] strings without E cannot generate E in result", "canonical_bson": "18000000136400185C0ACE00000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+345678.5432\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.5432\"}}" }, { "description": "[basx036] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640015CD5B0700000000000000000000203000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000000123456789\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.23456789E-8\"}}" }, { "description": "[basx035] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640015CD5B0700000000000000000000223000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000123456789\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.23456789E-7\"}}" }, { "description": "[basx034] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640015CD5B0700000000000000000000243000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000123456789\"}}" }, { "description": "[basx053] strings without E cannot generate E in result", "canonical_bson": "180000001364003200000000000000000000000000323000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000050\"}}" }, { "description": "[basx033] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640015CD5B0700000000000000000000263000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000123456789\"}}" }, { "description": "[basx016] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364000C000000000000000000000000003A3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.012\"}}" }, { "description": "[basx015] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364007B000000000000000000000000003A3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.123\"}}" }, { "description": "[basx037] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640078DF0D8648700000000000000000223000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.123456789012344\"}}" }, { "description": "[basx038] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640079DF0D8648700000000000000000223000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.123456789012345\"}}" }, { "description": "[basx250] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000383000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}" }, { "description": "[basx257] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}" }, { "description": "[basx256] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000363000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.01265\"}}" }, { "description": "[basx258] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}" }, { "description": "[basx251] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000103000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-20\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-21\"}}" }, { "description": "[basx263] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000603000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+20\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+19\"}}" }, { "description": "[basx255] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000343000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.001265\"}}" }, { "description": "[basx259] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}" }, { "description": "[basx254] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000323000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0001265\"}}" }, { "description": "[basx260] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}" }, { "description": "[basx253] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000303000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00001265\"}}" }, { "description": "[basx261] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}" }, { "description": "[basx252] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000283000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-9\"}}" }, { "description": "[basx262] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000483000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+7\"}}" }, { "description": "[basx159] Numbers with E", "canonical_bson": "1800000013640049000000000000000000000000002E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.73e-7\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7.3E-8\"}}" }, { "description": "[basx004] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640064000000000000000000000000003C3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00\"}}" }, { "description": "[basx003] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364000A000000000000000000000000003E3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0\"}}" }, { "description": "[basx002] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364000100000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1\"}}" }, { "description": "[basx148] Numbers with E", "canonical_bson": "180000001364000100000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+009\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" }, { "description": "[basx153] Numbers with E", "canonical_bson": "180000001364000100000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E009\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" }, { "description": "[basx141] Numbers with E", "canonical_bson": "180000001364000100000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1e+09\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" }, { "description": "[basx146] Numbers with E", "canonical_bson": "180000001364000100000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+09\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" }, { "description": "[basx151] Numbers with E", "canonical_bson": "180000001364000100000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1e09\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" }, { "description": "[basx142] Numbers with E", "canonical_bson": "180000001364000100000000000000000000000000F43000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+90\"}}" }, { "description": "[basx147] Numbers with E", "canonical_bson": "180000001364000100000000000000000000000000F43000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1e+90\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+90\"}}" }, { "description": "[basx152] Numbers with E", "canonical_bson": "180000001364000100000000000000000000000000F43000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E90\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+90\"}}" }, { "description": "[basx140] Numbers with E", "canonical_bson": "180000001364000100000000000000000000000000523000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" }, { "description": "[basx150] Numbers with E", "canonical_bson": "180000001364000100000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" }, { "description": "[basx014] conform to rules and exponent will be in permitted range).", "canonical_bson": "18000000136400D2040000000000000000000000003A3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.234\"}}" }, { "description": "[basx170] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003A3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}" }, { "description": "[basx177] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}" }, { "description": "[basx176] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}" }, { "description": "[basx178] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}" }, { "description": "[basx171] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000123000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-20\"}}" }, { "description": "[basx183] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000623000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+20\"}}" }, { "description": "[basx175] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000363000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.01265\"}}" }, { "description": "[basx179] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}" }, { "description": "[basx174] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000343000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.001265\"}}" }, { "description": "[basx180] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}" }, { "description": "[basx173] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000323000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0001265\"}}" }, { "description": "[basx181] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000423000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+4\"}}" }, { "description": "[basx172] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000002A3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-8\"}}" }, { "description": "[basx182] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000004A3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+8\"}}" }, { "description": "[basx157] Numbers with E", "canonical_bson": "180000001364000400000000000000000000000000523000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"4E+9\"}}" }, { "description": "[basx067] examples", "canonical_bson": "180000001364000500000000000000000000000000343000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"5E-6\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000005\"}}" }, { "description": "[basx069] examples", "canonical_bson": "180000001364000500000000000000000000000000323000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"5E-7\"}}" }, { "description": "[basx385] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7\"}}" }, { "description": "[basx365] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000543000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E10\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+10\"}}" }, { "description": "[basx405] Engineering notation tests", "canonical_bson": "1800000013640007000000000000000000000000002C3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-10\"}}" }, { "description": "[basx363] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000563000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E11\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+11\"}}" }, { "description": "[basx407] Engineering notation tests", "canonical_bson": "1800000013640007000000000000000000000000002A3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-11\"}}" }, { "description": "[basx361] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000583000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E12\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+12\"}}" }, { "description": "[basx409] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000283000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-12\"}}" }, { "description": "[basx411] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000263000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-13\"}}" }, { "description": "[basx383] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000423000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+1\"}}" }, { "description": "[basx387] Engineering notation tests", "canonical_bson": "1800000013640007000000000000000000000000003E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.7\"}}" }, { "description": "[basx381] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000443000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+2\"}}" }, { "description": "[basx389] Engineering notation tests", "canonical_bson": "1800000013640007000000000000000000000000003C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.07\"}}" }, { "description": "[basx379] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000463000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+3\"}}" }, { "description": "[basx391] Engineering notation tests", "canonical_bson": "1800000013640007000000000000000000000000003A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.007\"}}" }, { "description": "[basx377] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000483000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+4\"}}" }, { "description": "[basx393] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0007\"}}" }, { "description": "[basx375] Engineering notation tests", "canonical_bson": "1800000013640007000000000000000000000000004A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E5\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+5\"}}" }, { "description": "[basx395] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000363000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-5\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00007\"}}" }, { "description": "[basx373] Engineering notation tests", "canonical_bson": "1800000013640007000000000000000000000000004C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E6\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+6\"}}" }, { "description": "[basx397] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000343000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-6\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000007\"}}" }, { "description": "[basx371] Engineering notation tests", "canonical_bson": "1800000013640007000000000000000000000000004E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E7\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+7\"}}" }, { "description": "[basx399] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000323000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-7\"}}" }, { "description": "[basx369] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000503000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+8\"}}" }, { "description": "[basx401] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000303000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-8\"}}" }, { "description": "[basx367] Engineering notation tests", "canonical_bson": "180000001364000700000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+9\"}}" }, { "description": "[basx403] Engineering notation tests", "canonical_bson": "1800000013640007000000000000000000000000002E3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-9\"}}" }, { "description": "[basx007] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640064000000000000000000000000003E3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10.0\"}}" }, { "description": "[basx005] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364000A00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10\"}}" }, { "description": "[basx165] Numbers with E", "canonical_bson": "180000001364000A00000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10E+009\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+10\"}}" }, { "description": "[basx163] Numbers with E", "canonical_bson": "180000001364000A00000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10E+09\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+10\"}}" }, { "description": "[basx325] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10\"}}" }, { "description": "[basx305] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000543000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e10\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+11\"}}" }, { "description": "[basx345] Engineering notation tests", "canonical_bson": "180000001364000A000000000000000000000000002C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-10\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-9\"}}" }, { "description": "[basx303] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000563000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e11\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+12\"}}" }, { "description": "[basx347] Engineering notation tests", "canonical_bson": "180000001364000A000000000000000000000000002A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-11\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-10\"}}" }, { "description": "[basx301] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000583000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e12\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+13\"}}" }, { "description": "[basx349] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000283000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-12\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-11\"}}" }, { "description": "[basx351] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000263000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-13\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-12\"}}" }, { "description": "[basx323] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000423000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+2\"}}" }, { "description": "[basx327] Engineering notation tests", "canonical_bson": "180000001364000A000000000000000000000000003E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0\"}}" }, { "description": "[basx321] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000443000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+3\"}}" }, { "description": "[basx329] Engineering notation tests", "canonical_bson": "180000001364000A000000000000000000000000003C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.10\"}}" }, { "description": "[basx319] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000463000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+4\"}}" }, { "description": "[basx331] Engineering notation tests", "canonical_bson": "180000001364000A000000000000000000000000003A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.010\"}}" }, { "description": "[basx317] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000483000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+5\"}}" }, { "description": "[basx333] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0010\"}}" }, { "description": "[basx315] Engineering notation tests", "canonical_bson": "180000001364000A000000000000000000000000004A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e5\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+6\"}}" }, { "description": "[basx335] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000363000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-5\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00010\"}}" }, { "description": "[basx313] Engineering notation tests", "canonical_bson": "180000001364000A000000000000000000000000004C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e6\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+7\"}}" }, { "description": "[basx337] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000343000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-6\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000010\"}}" }, { "description": "[basx311] Engineering notation tests", "canonical_bson": "180000001364000A000000000000000000000000004E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e7\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+8\"}}" }, { "description": "[basx339] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000323000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-7\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000010\"}}" }, { "description": "[basx309] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000503000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+9\"}}" }, { "description": "[basx341] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000303000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-7\"}}" }, { "description": "[basx164] Numbers with E", "canonical_bson": "180000001364000A00000000000000000000000000F43000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e+90\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+91\"}}" }, { "description": "[basx162] Numbers with E", "canonical_bson": "180000001364000A00000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10E+9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+10\"}}" }, { "description": "[basx307] Engineering notation tests", "canonical_bson": "180000001364000A00000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+10\"}}" }, { "description": "[basx343] Engineering notation tests", "canonical_bson": "180000001364000A000000000000000000000000002E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-8\"}}" }, { "description": "[basx008] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640065000000000000000000000000003E3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10.1\"}}" }, { "description": "[basx009] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640068000000000000000000000000003E3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10.4\"}}" }, { "description": "[basx010] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640069000000000000000000000000003E3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10.5\"}}" }, { "description": "[basx011] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364006A000000000000000000000000003E3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10.6\"}}" }, { "description": "[basx012] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364006D000000000000000000000000003E3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10.9\"}}" }, { "description": "[basx013] conform to rules and exponent will be in permitted range).", "canonical_bson": "180000001364006E000000000000000000000000003E3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"11.0\"}}" }, { "description": "[basx040] strings without E cannot generate E in result", "canonical_bson": "180000001364000C00000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12\"}}" }, { "description": "[basx190] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003C3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}" }, { "description": "[basx197] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}" }, { "description": "[basx196] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}" }, { "description": "[basx198] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}" }, { "description": "[basx191] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000143000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-20\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-19\"}}" }, { "description": "[basx203] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000643000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+20\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+21\"}}" }, { "description": "[basx195] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}" }, { "description": "[basx199] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}" }, { "description": "[basx194] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000363000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.01265\"}}" }, { "description": "[basx200] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000423000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+4\"}}" }, { "description": "[basx193] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000343000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.001265\"}}" }, { "description": "[basx201] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000443000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+5\"}}" }, { "description": "[basx192] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000002C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-7\"}}" }, { "description": "[basx202] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000004C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+9\"}}" }, { "description": "[basx044] strings without E cannot generate E in result", "canonical_bson": "18000000136400FC040000000000000000000000003C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"012.76\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.76\"}}" }, { "description": "[basx042] strings without E cannot generate E in result", "canonical_bson": "18000000136400FC040000000000000000000000003C3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.76\"}}" }, { "description": "[basx046] strings without E cannot generate E in result", "canonical_bson": "180000001364001100000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"17.\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"17\"}}" }, { "description": "[basx049] strings without E cannot generate E in result", "canonical_bson": "180000001364002C00000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0044\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"44\"}}" }, { "description": "[basx048] strings without E cannot generate E in result", "canonical_bson": "180000001364002C00000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"044\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"44\"}}" }, { "description": "[basx158] Numbers with E", "canonical_bson": "180000001364002C00000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"44E+9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"4.4E+10\"}}" }, { "description": "[basx068] examples", "canonical_bson": "180000001364003200000000000000000000000000323000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"50E-7\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000050\"}}" }, { "description": "[basx169] Numbers with E", "canonical_bson": "180000001364006400000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"100e+009\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+11\"}}" }, { "description": "[basx167] Numbers with E", "canonical_bson": "180000001364006400000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"100e+09\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+11\"}}" }, { "description": "[basx168] Numbers with E", "canonical_bson": "180000001364006400000000000000000000000000F43000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"100E+90\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+92\"}}" }, { "description": "[basx166] Numbers with E", "canonical_bson": "180000001364006400000000000000000000000000523000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"100e+9\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+11\"}}" }, { "description": "[basx210] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003E3000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}" }, { "description": "[basx217] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}" }, { "description": "[basx216] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}" }, { "description": "[basx218] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}" }, { "description": "[basx211] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000163000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-20\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-18\"}}" }, { "description": "[basx223] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000663000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+20\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+22\"}}" }, { "description": "[basx215] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}" }, { "description": "[basx219] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000423000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+4\"}}" }, { "description": "[basx214] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}" }, { "description": "[basx220] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000443000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+5\"}}" }, { "description": "[basx213] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000363000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.01265\"}}" }, { "description": "[basx221] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000463000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+6\"}}" }, { "description": "[basx212] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000002E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000001265\"}}" }, { "description": "[basx222] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000004E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+10\"}}" }, { "description": "[basx006] conform to rules and exponent will be in permitted range).", "canonical_bson": "18000000136400E803000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1000\"}}" }, { "description": "[basx230] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}" }, { "description": "[basx237] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000403000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}" }, { "description": "[basx236] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}" }, { "description": "[basx238] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000423000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+1\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+4\"}}" }, { "description": "[basx231] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000183000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-20\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-17\"}}" }, { "description": "[basx243] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000683000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+20\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+23\"}}" }, { "description": "[basx235] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}" }, { "description": "[basx239] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000443000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+2\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+5\"}}" }, { "description": "[basx234] Numbers with E", "canonical_bson": "18000000136400F1040000000000000000000000003A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}" }, { "description": "[basx240] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000463000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+3\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+6\"}}" }, { "description": "[basx233] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000383000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}" }, { "description": "[basx241] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000483000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+4\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+7\"}}" }, { "description": "[basx232] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000303000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00001265\"}}" }, { "description": "[basx242] Numbers with E", "canonical_bson": "18000000136400F104000000000000000000000000503000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+8\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+11\"}}" }, { "description": "[basx060] strings without E cannot generate E in result", "canonical_bson": "18000000136400185C0ACE00000000000000000000383000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.5432\"}}" }, { "description": "[basx059] strings without E cannot generate E in result", "canonical_bson": "18000000136400F198670C08000000000000000000363000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0345678.54321\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.54321\"}}" }, { "description": "[basx058] strings without E cannot generate E in result", "canonical_bson": "180000001364006AF90B7C50000000000000000000343000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.543210\"}}" }, { "description": "[basx057] strings without E cannot generate E in result", "canonical_bson": "180000001364006A19562522020000000000000000343000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2345678.543210\"}}" }, { "description": "[basx056] strings without E cannot generate E in result", "canonical_bson": "180000001364006AB9C8733A0B0000000000000000343000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12345678.543210\"}}" }, { "description": "[basx031] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640040AF0D8648700000000000000000343000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"123456789.000000\"}}" }, { "description": "[basx030] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640080910F8648700000000000000000343000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"123456789.123456\"}}" }, { "description": "[basx032] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640080910F8648700000000000000000403000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"123456789123456\"}}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/decimal128-4.json000066400000000000000000000122651423026727100237520ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "valid": [ { "description": "[basx023] conform to rules and exponent will be in permitted range).", "canonical_bson": "1800000013640001000000000000000000000000003EB000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.1\"}}" }, { "description": "[basx045] strings without E cannot generate E in result", "canonical_bson": "1800000013640003000000000000000000000000003A3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+0.003\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.003\"}}" }, { "description": "[basx610] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \".0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}" }, { "description": "[basx612] Zeros", "canonical_bson": "1800000013640000000000000000000000000000003EB000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-.0\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0\"}}" }, { "description": "[basx043] strings without E cannot generate E in result", "canonical_bson": "18000000136400FC040000000000000000000000003C3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+12.76\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.76\"}}" }, { "description": "[basx055] strings without E cannot generate E in result", "canonical_bson": "180000001364000500000000000000000000000000303000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000005\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"5E-8\"}}" }, { "description": "[basx054] strings without E cannot generate E in result", "canonical_bson": "180000001364000500000000000000000000000000323000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000005\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"5E-7\"}}" }, { "description": "[basx052] strings without E cannot generate E in result", "canonical_bson": "180000001364000500000000000000000000000000343000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000005\"}}" }, { "description": "[basx051] strings without E cannot generate E in result", "canonical_bson": "180000001364000500000000000000000000000000363000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"00.00005\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00005\"}}" }, { "description": "[basx050] strings without E cannot generate E in result", "canonical_bson": "180000001364000500000000000000000000000000383000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0005\"}}" }, { "description": "[basx047] strings without E cannot generate E in result", "canonical_bson": "1800000013640005000000000000000000000000003E3000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \".5\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.5\"}}" }, { "description": "[dqbsr431] check rounding modes heeded (Rounded)", "canonical_bson": "1800000013640099761CC7B548F377DC80A131C836FE2F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.1111111111111111111111111111123450\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.111111111111111111111111111112345\"}}" }, { "description": "OK2", "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FC2F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \".100000000000000000000000000000000000000000000000000000000000\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1000000000000000000000000000000000\"}}" } ], "parseErrors": [ { "description": "[basx564] Near-specials (Conversion_syntax)", "string": "Infi" }, { "description": "[basx565] Near-specials (Conversion_syntax)", "string": "Infin" }, { "description": "[basx566] Near-specials (Conversion_syntax)", "string": "Infini" }, { "description": "[basx567] Near-specials (Conversion_syntax)", "string": "Infinit" }, { "description": "[basx568] Near-specials (Conversion_syntax)", "string": "-Infinit" }, { "description": "[basx590] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": ".Infinity" }, { "description": "[basx562] Near-specials (Conversion_syntax)", "string": "NaNq" }, { "description": "[basx563] Near-specials (Conversion_syntax)", "string": "NaNs" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/decimal128-5.json000066400000000000000000000554551423026727100237630ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "valid": [ { "description": "[decq035] fold-downs (more below) (Clamped)", "canonical_bson": "18000000136400000000807F1BCF85B27059C8A43CFE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.23E+6144\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.230000000000000000000000000000000E+6144\"}}" }, { "description": "[decq037] fold-downs (more below) (Clamped)", "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6144\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}" }, { "description": "[decq077] Nmin and below (Subnormal)", "canonical_bson": "180000001364000000000081EFAC855B416D2DEE04000000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.100000000000000000000000000000000E-6143\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000000E-6144\"}}" }, { "description": "[decq078] Nmin and below (Subnormal)", "canonical_bson": "180000001364000000000081EFAC855B416D2DEE04000000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000000E-6144\"}}" }, { "description": "[decq079] Nmin and below (Subnormal)", "canonical_bson": "180000001364000A00000000000000000000000000000000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000000000000000000000000000010E-6143\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-6175\"}}" }, { "description": "[decq080] Nmin and below (Subnormal)", "canonical_bson": "180000001364000A00000000000000000000000000000000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-6175\"}}" }, { "description": "[decq081] Nmin and below (Subnormal)", "canonical_bson": "180000001364000100000000000000000000000000020000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000000000000000000000000000001E-6143\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6175\"}}" }, { "description": "[decq082] Nmin and below (Subnormal)", "canonical_bson": "180000001364000100000000000000000000000000020000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6175\"}}" }, { "description": "[decq083] Nmin and below (Subnormal)", "canonical_bson": "180000001364000100000000000000000000000000000000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000000000000000000000000000001E-6143\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}" }, { "description": "[decq084] Nmin and below (Subnormal)", "canonical_bson": "180000001364000100000000000000000000000000000000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}" }, { "description": "[decq090] underflows cannot be tested for simple copies, check edge cases (Subnormal)", "canonical_bson": "180000001364000100000000000000000000000000000000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1e-6176\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}" }, { "description": "[decq100] underflows cannot be tested for simple copies, check edge cases (Subnormal)", "canonical_bson": "18000000136400FFFFFFFF095BC138938D44C64D31000000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"999999999999999999999999999999999e-6176\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"9.99999999999999999999999999999999E-6144\"}}" }, { "description": "[decq130] fold-downs (more below) (Clamped)", "canonical_bson": "18000000136400000000807F1BCF85B27059C8A43CFEDF00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.23E+6144\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.230000000000000000000000000000000E+6144\"}}" }, { "description": "[decq132] fold-downs (more below) (Clamped)", "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FEDF00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E+6144\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.000000000000000000000000000000000E+6144\"}}" }, { "description": "[decq177] Nmin and below (Subnormal)", "canonical_bson": "180000001364000000000081EFAC855B416D2DEE04008000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.100000000000000000000000000000000E-6143\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.00000000000000000000000000000000E-6144\"}}" }, { "description": "[decq178] Nmin and below (Subnormal)", "canonical_bson": "180000001364000000000081EFAC855B416D2DEE04008000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.00000000000000000000000000000000E-6144\"}}" }, { "description": "[decq179] Nmin and below (Subnormal)", "canonical_bson": "180000001364000A00000000000000000000000000008000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000000000000000000000000000010E-6143\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.0E-6175\"}}" }, { "description": "[decq180] Nmin and below (Subnormal)", "canonical_bson": "180000001364000A00000000000000000000000000008000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.0E-6175\"}}" }, { "description": "[decq181] Nmin and below (Subnormal)", "canonical_bson": "180000001364000100000000000000000000000000028000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000000000000000000000000000001E-6143\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6175\"}}" }, { "description": "[decq182] Nmin and below (Subnormal)", "canonical_bson": "180000001364000100000000000000000000000000028000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6175\"}}" }, { "description": "[decq183] Nmin and below (Subnormal)", "canonical_bson": "180000001364000100000000000000000000000000008000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000000000000000000000000000001E-6143\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6176\"}}" }, { "description": "[decq184] Nmin and below (Subnormal)", "canonical_bson": "180000001364000100000000000000000000000000008000", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6176\"}}" }, { "description": "[decq190] underflow edge cases (Subnormal)", "canonical_bson": "180000001364000100000000000000000000000000008000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1e-6176\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6176\"}}" }, { "description": "[decq200] underflow edge cases (Subnormal)", "canonical_bson": "18000000136400FFFFFFFF095BC138938D44C64D31008000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-999999999999999999999999999999999e-6176\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.99999999999999999999999999999999E-6144\"}}" }, { "description": "[decq400] zeros (Clamped)", "canonical_bson": "180000001364000000000000000000000000000000000000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-8000\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6176\"}}" }, { "description": "[decq401] zeros (Clamped)", "canonical_bson": "180000001364000000000000000000000000000000000000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6177\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6176\"}}" }, { "description": "[decq414] clamped zeros... (Clamped)", "canonical_bson": "180000001364000000000000000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6112\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6111\"}}" }, { "description": "[decq416] clamped zeros... (Clamped)", "canonical_bson": "180000001364000000000000000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6144\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6111\"}}" }, { "description": "[decq418] clamped zeros... (Clamped)", "canonical_bson": "180000001364000000000000000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+8000\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6111\"}}" }, { "description": "[decq420] negative zeros (Clamped)", "canonical_bson": "180000001364000000000000000000000000000000008000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-8000\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6176\"}}" }, { "description": "[decq421] negative zeros (Clamped)", "canonical_bson": "180000001364000000000000000000000000000000008000", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6177\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6176\"}}" }, { "description": "[decq434] clamped zeros... (Clamped)", "canonical_bson": "180000001364000000000000000000000000000000FEDF00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6112\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6111\"}}" }, { "description": "[decq436] clamped zeros... (Clamped)", "canonical_bson": "180000001364000000000000000000000000000000FEDF00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6144\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6111\"}}" }, { "description": "[decq438] clamped zeros... (Clamped)", "canonical_bson": "180000001364000000000000000000000000000000FEDF00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+8000\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6111\"}}" }, { "description": "[decq601] fold-down full sequence (Clamped)", "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6144\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}" }, { "description": "[decq603] fold-down full sequence (Clamped)", "canonical_bson": "180000001364000000000081EFAC855B416D2DEE04FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6143\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000000E+6143\"}}" }, { "description": "[decq605] fold-down full sequence (Clamped)", "canonical_bson": "1800000013640000000080264B91C02220BE377E00FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6142\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000000000E+6142\"}}" }, { "description": "[decq607] fold-down full sequence (Clamped)", "canonical_bson": "1800000013640000000040EAED7446D09C2C9F0C00FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6141\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000E+6141\"}}" }, { "description": "[decq609] fold-down full sequence (Clamped)", "canonical_bson": "18000000136400000000A0CA17726DAE0F1E430100FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6140\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000E+6140\"}}" }, { "description": "[decq611] fold-down full sequence (Clamped)", "canonical_bson": "18000000136400000000106102253E5ECE4F200000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6139\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000000E+6139\"}}" }, { "description": "[decq613] fold-down full sequence (Clamped)", "canonical_bson": "18000000136400000000E83C80D09F3C2E3B030000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6138\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000E+6138\"}}" }, { "description": "[decq615] fold-down full sequence (Clamped)", "canonical_bson": "18000000136400000000E4D20CC8DCD2B752000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6137\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000E+6137\"}}" }, { "description": "[decq617] fold-down full sequence (Clamped)", "canonical_bson": "180000001364000000004A48011416954508000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6136\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000E+6136\"}}" }, { "description": "[decq619] fold-down full sequence (Clamped)", "canonical_bson": "18000000136400000000A1EDCCCE1BC2D300000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6135\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000E+6135\"}}" }, { "description": "[decq621] fold-down full sequence (Clamped)", "canonical_bson": "18000000136400000080F64AE1C7022D1500000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6134\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000E+6134\"}}" }, { "description": "[decq623] fold-down full sequence (Clamped)", "canonical_bson": "18000000136400000040B2BAC9E0191E0200000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6133\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000E+6133\"}}" }, { "description": "[decq625] fold-down full sequence (Clamped)", "canonical_bson": "180000001364000000A0DEC5ADC935360000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6132\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000E+6132\"}}" }, { "description": "[decq627] fold-down full sequence (Clamped)", "canonical_bson": "18000000136400000010632D5EC76B050000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6131\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000E+6131\"}}" }, { "description": "[decq629] fold-down full sequence (Clamped)", "canonical_bson": "180000001364000000E8890423C78A000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6130\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000E+6130\"}}" }, { "description": "[decq631] fold-down full sequence (Clamped)", "canonical_bson": "18000000136400000064A7B3B6E00D000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6129\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000E+6129\"}}" }, { "description": "[decq633] fold-down full sequence (Clamped)", "canonical_bson": "1800000013640000008A5D78456301000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6128\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000E+6128\"}}" }, { "description": "[decq635] fold-down full sequence (Clamped)", "canonical_bson": "180000001364000000C16FF2862300000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6127\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000E+6127\"}}" }, { "description": "[decq637] fold-down full sequence (Clamped)", "canonical_bson": "180000001364000080C6A47E8D0300000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6126\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000E+6126\"}}" }, { "description": "[decq639] fold-down full sequence (Clamped)", "canonical_bson": "1800000013640000407A10F35A0000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6125\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000E+6125\"}}" }, { "description": "[decq641] fold-down full sequence (Clamped)", "canonical_bson": "1800000013640000A0724E18090000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6124\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000E+6124\"}}" }, { "description": "[decq643] fold-down full sequence (Clamped)", "canonical_bson": "180000001364000010A5D4E8000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6123\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000E+6123\"}}" }, { "description": "[decq645] fold-down full sequence (Clamped)", "canonical_bson": "1800000013640000E8764817000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6122\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000E+6122\"}}" }, { "description": "[decq647] fold-down full sequence (Clamped)", "canonical_bson": "1800000013640000E40B5402000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6121\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000E+6121\"}}" }, { "description": "[decq649] fold-down full sequence (Clamped)", "canonical_bson": "1800000013640000CA9A3B00000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6120\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000E+6120\"}}" }, { "description": "[decq651] fold-down full sequence (Clamped)", "canonical_bson": "1800000013640000E1F50500000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6119\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000E+6119\"}}" }, { "description": "[decq653] fold-down full sequence (Clamped)", "canonical_bson": "180000001364008096980000000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6118\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000E+6118\"}}" }, { "description": "[decq655] fold-down full sequence (Clamped)", "canonical_bson": "1800000013640040420F0000000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6117\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000E+6117\"}}" }, { "description": "[decq657] fold-down full sequence (Clamped)", "canonical_bson": "18000000136400A086010000000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6116\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000E+6116\"}}" }, { "description": "[decq659] fold-down full sequence (Clamped)", "canonical_bson": "180000001364001027000000000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6115\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000E+6115\"}}" }, { "description": "[decq661] fold-down full sequence (Clamped)", "canonical_bson": "18000000136400E803000000000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6114\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000E+6114\"}}" }, { "description": "[decq663] fold-down full sequence (Clamped)", "canonical_bson": "180000001364006400000000000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6113\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+6113\"}}" }, { "description": "[decq665] fold-down full sequence (Clamped)", "canonical_bson": "180000001364000A00000000000000000000000000FE5F00", "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6112\"}}", "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+6112\"}}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/decimal128-6.json000066400000000000000000000053011423026727100237450ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "parseErrors": [ { "description": "Incomplete Exponent", "string": "1e" }, { "description": "Exponent at the beginning", "string": "E01" }, { "description": "Just a decimal place", "string": "." }, { "description": "2 decimal places", "string": "..3" }, { "description": "2 decimal places", "string": ".13.3" }, { "description": "2 decimal places", "string": "1..3" }, { "description": "2 decimal places", "string": "1.3.4" }, { "description": "2 decimal places", "string": "1.34." }, { "description": "Decimal with no digits", "string": ".e" }, { "description": "2 signs", "string": "+-32.4" }, { "description": "2 signs", "string": "-+32.4" }, { "description": "2 negative signs", "string": "--32.4" }, { "description": "2 negative signs", "string": "-32.-4" }, { "description": "End in negative sign", "string": "32.0-" }, { "description": "2 negative signs", "string": "32.4E--21" }, { "description": "2 negative signs", "string": "32.4E-2-1" }, { "description": "2 signs", "string": "32.4E+-21" }, { "description": "Empty string", "string": "" }, { "description": "Invalid", "string": "E" }, { "description": "Invalid", "string": "invalid" }, { "description": "Invalid", "string": "i" }, { "description": "Invalid", "string": "in" }, { "description": "Invalid", "string": "-in" }, { "description": "Invalid", "string": "Na" }, { "description": "Invalid", "string": "-Na" }, { "description": "Invalid", "string": "1.23abc" }, { "description": "Invalid", "string": "1.23abcE+02" }, { "description": "Invalid", "string": "1.23E+0aabs2" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/decimal128-7.json000066400000000000000000000305541423026727100237560ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "parseErrors": [ { "description": "[basx572] Near-specials (Conversion_syntax)", "string": "-9Inf" }, { "description": "[basx516] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "-1-" }, { "description": "[basx533] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "0000.." }, { "description": "[basx534] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": ".0000." }, { "description": "[basx535] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "00..00" }, { "description": "[basx569] Near-specials (Conversion_syntax)", "string": "0Inf" }, { "description": "[basx571] Near-specials (Conversion_syntax)", "string": "-0Inf" }, { "description": "[basx575] Near-specials (Conversion_syntax)", "string": "0sNaN" }, { "description": "[basx503] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "++1" }, { "description": "[basx504] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "--1" }, { "description": "[basx505] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "-+1" }, { "description": "[basx506] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "+-1" }, { "description": "[basx510] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": " +1" }, { "description": "[basx513] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": " + 1" }, { "description": "[basx514] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": " - 1" }, { "description": "[basx501] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "." }, { "description": "[basx502] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": ".." }, { "description": "[basx519] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "" }, { "description": "[basx525] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "e100" }, { "description": "[basx549] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "e+1" }, { "description": "[basx577] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": ".e+1" }, { "description": "[basx578] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": "+.e+1" }, { "description": "[basx581] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": "E+1" }, { "description": "[basx582] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": ".E+1" }, { "description": "[basx583] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": "+.E+1" }, { "description": "[basx579] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": "-.e+" }, { "description": "[basx580] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": "-.e" }, { "description": "[basx584] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": "-.E+" }, { "description": "[basx585] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": "-.E" }, { "description": "[basx589] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": "+.Inf" }, { "description": "[basx586] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": ".NaN" }, { "description": "[basx587] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": "-.NaN" }, { "description": "[basx545] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "ONE" }, { "description": "[basx561] Near-specials (Conversion_syntax)", "string": "qNaN" }, { "description": "[basx573] Near-specials (Conversion_syntax)", "string": "-sNa" }, { "description": "[basx588] some baddies with dots and Es and dots and specials (Conversion_syntax)", "string": "+.sNaN" }, { "description": "[basx544] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "ten" }, { "description": "[basx527] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "u0b65" }, { "description": "[basx526] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "u0e5a" }, { "description": "[basx515] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "x" }, { "description": "[basx574] Near-specials (Conversion_syntax)", "string": "xNaN" }, { "description": "[basx530] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": ".123.5" }, { "description": "[basx500] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1..2" }, { "description": "[basx542] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1e1.0" }, { "description": "[basx553] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1E+1.2.3" }, { "description": "[basx543] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1e123e" }, { "description": "[basx552] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1E+1.2" }, { "description": "[basx546] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1e.1" }, { "description": "[basx547] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1e1." }, { "description": "[basx554] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1E++1" }, { "description": "[basx555] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1E--1" }, { "description": "[basx556] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1E+-1" }, { "description": "[basx557] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1E-+1" }, { "description": "[basx558] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1E'1" }, { "description": "[basx559] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1E\"1" }, { "description": "[basx520] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1e-" }, { "description": "[basx560] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1E" }, { "description": "[basx548] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1ee" }, { "description": "[basx551] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1.2.1" }, { "description": "[basx550] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1.23.4" }, { "description": "[basx529] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "1.34.5" }, { "description": "[basx531] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "01.35." }, { "description": "[basx532] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "01.35-" }, { "description": "[basx518] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "3+" }, { "description": "[basx521] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "7e99999a" }, { "description": "[basx570] Near-specials (Conversion_syntax)", "string": "9Inf" }, { "description": "[basx517] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "12-" }, { "description": "[basx507] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "12e" }, { "description": "[basx508] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "12e++" }, { "description": "[basx509] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "12f4" }, { "description": "[basx536] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "111e*123" }, { "description": "[basx537] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "111e123-" }, { "description": "[basx540] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "111e1*23" }, { "description": "[basx538] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "111e+12+" }, { "description": "[basx539] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "111e1-3-" }, { "description": "[basx541] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "111E1e+3" }, { "description": "[basx528] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "123,65" }, { "description": "[basx523] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "7e12356789012x" }, { "description": "[basx522] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "7e123567890x" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/document.json000066400000000000000000000026031423026727100235710ustar00rootroot00000000000000{ "description": "Document type (sub-documents)", "bson_type": "0x03", "test_key": "x", "valid": [ { "description": "Empty subdoc", "canonical_bson": "0D000000037800050000000000", "canonical_extjson": "{\"x\" : {}}" }, { "description": "Empty-string key subdoc", "canonical_bson": "150000000378000D00000002000200000062000000", "canonical_extjson": "{\"x\" : {\"\" : \"b\"}}" }, { "description": "Single-character key subdoc", "canonical_bson": "160000000378000E0000000261000200000062000000", "canonical_extjson": "{\"x\" : {\"a\" : \"b\"}}" } ], "decodeErrors": [ { "description": "Subdocument length too long: eats outer terminator", "bson": "1800000003666F6F000F0000001062617200FFFFFF7F0000" }, { "description": "Subdocument length too short: leaks terminator", "bson": "1500000003666F6F000A0000000862617200010000" }, { "description": "Invalid subdocument: bad string length in field", "bson": "1C00000003666F6F001200000002626172000500000062617A000000" }, { "description": "Null byte in sub-document key", "bson": "150000000378000D00000010610000010000000000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/double.json000066400000000000000000000067071423026727100232360ustar00rootroot00000000000000{ "description": "Double type", "bson_type": "0x01", "test_key": "d", "valid": [ { "description": "+1.0", "canonical_bson": "10000000016400000000000000F03F00", "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"1.0\"}}", "relaxed_extjson": "{\"d\" : 1.0}" }, { "description": "-1.0", "canonical_bson": "10000000016400000000000000F0BF00", "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"-1.0\"}}", "relaxed_extjson": "{\"d\" : -1.0}" }, { "description": "+1.0001220703125", "canonical_bson": "10000000016400000000008000F03F00", "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"1.0001220703125\"}}", "relaxed_extjson": "{\"d\" : 1.0001220703125}" }, { "description": "-1.0001220703125", "canonical_bson": "10000000016400000000008000F0BF00", "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"-1.0001220703125\"}}", "relaxed_extjson": "{\"d\" : -1.0001220703125}" }, { "description": "1.2345678921232E+18", "canonical_bson": "100000000164002a1bf5f41022b14300", "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"1.2345678921232E+18\"}}", "relaxed_extjson": "{\"d\" : 1.2345678921232E+18}" }, { "description": "-1.2345678921232E+18", "canonical_bson": "100000000164002a1bf5f41022b1c300", "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"-1.2345678921232E+18\"}}", "relaxed_extjson": "{\"d\" : -1.2345678921232E+18}" }, { "description": "0.0", "canonical_bson": "10000000016400000000000000000000", "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"0.0\"}}", "relaxed_extjson": "{\"d\" : 0.0}" }, { "description": "-0.0", "canonical_bson": "10000000016400000000000000008000", "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"-0.0\"}}", "relaxed_extjson": "{\"d\" : -0.0}" }, { "description": "NaN", "canonical_bson": "10000000016400000000000000F87F00", "canonical_extjson": "{\"d\": {\"$numberDouble\": \"NaN\"}}", "relaxed_extjson": "{\"d\": {\"$numberDouble\": \"NaN\"}}", "lossy": true }, { "description": "NaN with payload", "canonical_bson": "10000000016400120000000000F87F00", "canonical_extjson": "{\"d\": {\"$numberDouble\": \"NaN\"}}", "relaxed_extjson": "{\"d\": {\"$numberDouble\": \"NaN\"}}", "lossy": true }, { "description": "Inf", "canonical_bson": "10000000016400000000000000F07F00", "canonical_extjson": "{\"d\": {\"$numberDouble\": \"Infinity\"}}", "relaxed_extjson": "{\"d\": {\"$numberDouble\": \"Infinity\"}}" }, { "description": "-Inf", "canonical_bson": "10000000016400000000000000F0FF00", "canonical_extjson": "{\"d\": {\"$numberDouble\": \"-Infinity\"}}", "relaxed_extjson": "{\"d\": {\"$numberDouble\": \"-Infinity\"}}" } ], "decodeErrors": [ { "description": "double truncated", "bson": "0B0000000164000000F03F00" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/int32.json000066400000000000000000000026271423026727100227200ustar00rootroot00000000000000{ "description": "Int32 type", "bson_type": "0x10", "test_key": "i", "valid": [ { "description": "MinValue", "canonical_bson": "0C0000001069000000008000", "canonical_extjson": "{\"i\" : {\"$numberInt\": \"-2147483648\"}}", "relaxed_extjson": "{\"i\" : -2147483648}" }, { "description": "MaxValue", "canonical_bson": "0C000000106900FFFFFF7F00", "canonical_extjson": "{\"i\" : {\"$numberInt\": \"2147483647\"}}", "relaxed_extjson": "{\"i\" : 2147483647}" }, { "description": "-1", "canonical_bson": "0C000000106900FFFFFFFF00", "canonical_extjson": "{\"i\" : {\"$numberInt\": \"-1\"}}", "relaxed_extjson": "{\"i\" : -1}" }, { "description": "0", "canonical_bson": "0C0000001069000000000000", "canonical_extjson": "{\"i\" : {\"$numberInt\": \"0\"}}", "relaxed_extjson": "{\"i\" : 0}" }, { "description": "1", "canonical_bson": "0C0000001069000100000000", "canonical_extjson": "{\"i\" : {\"$numberInt\": \"1\"}}", "relaxed_extjson": "{\"i\" : 1}" } ], "decodeErrors": [ { "description": "Bad int32 field length", "bson": "090000001061000500" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/int64.json000066400000000000000000000027621423026727100227250ustar00rootroot00000000000000{ "description": "Int64 type", "bson_type": "0x12", "test_key": "a", "valid": [ { "description": "MinValue", "canonical_bson": "10000000126100000000000000008000", "canonical_extjson": "{\"a\" : {\"$numberLong\" : \"-9223372036854775808\"}}", "relaxed_extjson": "{\"a\" : -9223372036854775808}" }, { "description": "MaxValue", "canonical_bson": "10000000126100FFFFFFFFFFFFFF7F00", "canonical_extjson": "{\"a\" : {\"$numberLong\" : \"9223372036854775807\"}}", "relaxed_extjson": "{\"a\" : 9223372036854775807}" }, { "description": "-1", "canonical_bson": "10000000126100FFFFFFFFFFFFFFFF00", "canonical_extjson": "{\"a\" : {\"$numberLong\" : \"-1\"}}", "relaxed_extjson": "{\"a\" : -1}" }, { "description": "0", "canonical_bson": "10000000126100000000000000000000", "canonical_extjson": "{\"a\" : {\"$numberLong\" : \"0\"}}", "relaxed_extjson": "{\"a\" : 0}" }, { "description": "1", "canonical_bson": "10000000126100010000000000000000", "canonical_extjson": "{\"a\" : {\"$numberLong\" : \"1\"}}", "relaxed_extjson": "{\"a\" : 1}" } ], "decodeErrors": [ { "description": "int64 field truncated", "bson": "0C0000001261001234567800" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/maxkey.json000066400000000000000000000004231423026727100232470ustar00rootroot00000000000000{ "description": "Maxkey type", "bson_type": "0x7F", "test_key": "a", "valid": [ { "description": "Maxkey", "canonical_bson": "080000007F610000", "canonical_extjson": "{\"a\" : {\"$maxKey\" : 1}}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/minkey.json000066400000000000000000000004231423026727100232450ustar00rootroot00000000000000{ "description": "Minkey type", "bson_type": "0xFF", "test_key": "a", "valid": [ { "description": "Minkey", "canonical_bson": "08000000FF610000", "canonical_extjson": "{\"a\" : {\"$minKey\" : 1}}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/multi-type-deprecated.json000066400000000000000000000124541423026727100261670ustar00rootroot00000000000000{ "description": "Multiple types within the same document", "bson_type": "0x00", "deprecated": true, "valid": [ { "description": "All BSON types", "canonical_bson": "38020000075F69640057E193D7A9CC81B4027498B50E53796D626F6C000700000073796D626F6C0002537472696E670007000000737472696E670010496E743332002A00000012496E743634002A0000000000000001446F75626C6500000000000000F0BF0542696E617279001000000003A34C38F7C3ABEDC8A37814A992AB8DB60542696E61727955736572446566696E656400050000008001020304050D436F6465000E00000066756E6374696F6E2829207B7D000F436F64655769746853636F7065001B0000000E00000066756E6374696F6E2829207B7D00050000000003537562646F63756D656E74001200000002666F6F0004000000626172000004417272617900280000001030000100000010310002000000103200030000001033000400000010340005000000001154696D657374616D7000010000002A0000000B5265676578007061747465726E0000094461746574696D6545706F6368000000000000000000094461746574696D65506F73697469766500FFFFFF7F00000000094461746574696D654E656761746976650000000080FFFFFFFF085472756500010846616C736500000C4442506F696E746572000B000000636F6C6C656374696F6E0057E193D7A9CC81B4027498B1034442526566003D0000000224726566000B000000636F6C6C656374696F6E00072469640057FD71E96E32AB4225B723FB02246462000900000064617461626173650000FF4D696E6B6579007F4D61786B6579000A4E756C6C0006556E646566696E65640000", "converted_bson": "48020000075f69640057e193d7a9cc81b4027498b50253796d626f6c000700000073796d626f6c0002537472696e670007000000737472696e670010496e743332002a00000012496e743634002a0000000000000001446f75626c6500000000000000f0bf0542696e617279001000000003a34c38f7c3abedc8a37814a992ab8db60542696e61727955736572446566696e656400050000008001020304050d436f6465000e00000066756e6374696f6e2829207b7d000f436f64655769746853636f7065001b0000000e00000066756e6374696f6e2829207b7d00050000000003537562646f63756d656e74001200000002666f6f0004000000626172000004417272617900280000001030000100000010310002000000103200030000001033000400000010340005000000001154696d657374616d7000010000002a0000000b5265676578007061747465726e0000094461746574696d6545706f6368000000000000000000094461746574696d65506f73697469766500ffffff7f00000000094461746574696d654e656761746976650000000080ffffffff085472756500010846616c73650000034442506f696e746572002b0000000224726566000b000000636f6c6c656374696f6e00072469640057e193d7a9cc81b4027498b100034442526566003d0000000224726566000b000000636f6c6c656374696f6e00072469640057fd71e96e32ab4225b723fb02246462000900000064617461626173650000ff4d696e6b6579007f4d61786b6579000a4e756c6c000a556e646566696e65640000", "canonical_extjson": "{\"_id\": {\"$oid\": \"57e193d7a9cc81b4027498b5\"}, \"Symbol\": {\"$symbol\": \"symbol\"}, \"String\": \"string\", \"Int32\": {\"$numberInt\": \"42\"}, \"Int64\": {\"$numberLong\": \"42\"}, \"Double\": {\"$numberDouble\": \"-1.0\"}, \"Binary\": { \"$binary\" : {\"base64\": \"o0w498Or7cijeBSpkquNtg==\", \"subType\": \"03\"}}, \"BinaryUserDefined\": { \"$binary\" : {\"base64\": \"AQIDBAU=\", \"subType\": \"80\"}}, \"Code\": {\"$code\": \"function() {}\"}, \"CodeWithScope\": {\"$code\": \"function() {}\", \"$scope\": {}}, \"Subdocument\": {\"foo\": \"bar\"}, \"Array\": [{\"$numberInt\": \"1\"}, {\"$numberInt\": \"2\"}, {\"$numberInt\": \"3\"}, {\"$numberInt\": \"4\"}, {\"$numberInt\": \"5\"}], \"Timestamp\": {\"$timestamp\": {\"t\": 42, \"i\": 1}}, \"Regex\": {\"$regularExpression\": {\"pattern\": \"pattern\", \"options\": \"\"}}, \"DatetimeEpoch\": {\"$date\": {\"$numberLong\": \"0\"}}, \"DatetimePositive\": {\"$date\": {\"$numberLong\": \"2147483647\"}}, \"DatetimeNegative\": {\"$date\": {\"$numberLong\": \"-2147483648\"}}, \"True\": true, \"False\": false, \"DBPointer\": {\"$dbPointer\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"57e193d7a9cc81b4027498b1\"}}}, \"DBRef\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"57fd71e96e32ab4225b723fb\"}, \"$db\": \"database\"}, \"Minkey\": {\"$minKey\": 1}, \"Maxkey\": {\"$maxKey\": 1}, \"Null\": null, \"Undefined\": {\"$undefined\": true}}", "converted_extjson": "{\"_id\": {\"$oid\": \"57e193d7a9cc81b4027498b5\"}, \"Symbol\": \"symbol\", \"String\": \"string\", \"Int32\": {\"$numberInt\": \"42\"}, \"Int64\": {\"$numberLong\": \"42\"}, \"Double\": {\"$numberDouble\": \"-1.0\"}, \"Binary\": { \"$binary\" : {\"base64\": \"o0w498Or7cijeBSpkquNtg==\", \"subType\": \"03\"}}, \"BinaryUserDefined\": { \"$binary\" : {\"base64\": \"AQIDBAU=\", \"subType\": \"80\"}}, \"Code\": {\"$code\": \"function() {}\"}, \"CodeWithScope\": {\"$code\": \"function() {}\", \"$scope\": {}}, \"Subdocument\": {\"foo\": \"bar\"}, \"Array\": [{\"$numberInt\": \"1\"}, {\"$numberInt\": \"2\"}, {\"$numberInt\": \"3\"}, {\"$numberInt\": \"4\"}, {\"$numberInt\": \"5\"}], \"Timestamp\": {\"$timestamp\": {\"t\": 42, \"i\": 1}}, \"Regex\": {\"$regularExpression\": {\"pattern\": \"pattern\", \"options\": \"\"}}, \"DatetimeEpoch\": {\"$date\": {\"$numberLong\": \"0\"}}, \"DatetimePositive\": {\"$date\": {\"$numberLong\": \"2147483647\"}}, \"DatetimeNegative\": {\"$date\": {\"$numberLong\": \"-2147483648\"}}, \"True\": true, \"False\": false, \"DBPointer\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"57e193d7a9cc81b4027498b1\"}}, \"DBRef\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"57fd71e96e32ab4225b723fb\"}, \"$db\": \"database\"}, \"Minkey\": {\"$minKey\": 1}, \"Maxkey\": {\"$maxKey\": 1}, \"Null\": null, \"Undefined\": null}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/multi-type.json000066400000000000000000000046451423026727100240740ustar00rootroot00000000000000{ "description": "Multiple types within the same document", "bson_type": "0x00", "valid": [ { "description": "All BSON types", "canonical_bson": "F4010000075F69640057E193D7A9CC81B4027498B502537472696E670007000000737472696E670010496E743332002A00000012496E743634002A0000000000000001446F75626C6500000000000000F0BF0542696E617279001000000003A34C38F7C3ABEDC8A37814A992AB8DB60542696E61727955736572446566696E656400050000008001020304050D436F6465000E00000066756E6374696F6E2829207B7D000F436F64655769746853636F7065001B0000000E00000066756E6374696F6E2829207B7D00050000000003537562646F63756D656E74001200000002666F6F0004000000626172000004417272617900280000001030000100000010310002000000103200030000001033000400000010340005000000001154696D657374616D7000010000002A0000000B5265676578007061747465726E0000094461746574696D6545706F6368000000000000000000094461746574696D65506F73697469766500FFFFFF7F00000000094461746574696D654E656761746976650000000080FFFFFFFF085472756500010846616C73650000034442526566003D0000000224726566000B000000636F6C6C656374696F6E00072469640057FD71E96E32AB4225B723FB02246462000900000064617461626173650000FF4D696E6B6579007F4D61786B6579000A4E756C6C0000", "canonical_extjson": "{\"_id\": {\"$oid\": \"57e193d7a9cc81b4027498b5\"}, \"String\": \"string\", \"Int32\": {\"$numberInt\": \"42\"}, \"Int64\": {\"$numberLong\": \"42\"}, \"Double\": {\"$numberDouble\": \"-1.0\"}, \"Binary\": { \"$binary\" : {\"base64\": \"o0w498Or7cijeBSpkquNtg==\", \"subType\": \"03\"}}, \"BinaryUserDefined\": { \"$binary\" : {\"base64\": \"AQIDBAU=\", \"subType\": \"80\"}}, \"Code\": {\"$code\": \"function() {}\"}, \"CodeWithScope\": {\"$code\": \"function() {}\", \"$scope\": {}}, \"Subdocument\": {\"foo\": \"bar\"}, \"Array\": [{\"$numberInt\": \"1\"}, {\"$numberInt\": \"2\"}, {\"$numberInt\": \"3\"}, {\"$numberInt\": \"4\"}, {\"$numberInt\": \"5\"}], \"Timestamp\": {\"$timestamp\": {\"t\": 42, \"i\": 1}}, \"Regex\": {\"$regularExpression\": {\"pattern\": \"pattern\", \"options\": \"\"}}, \"DatetimeEpoch\": {\"$date\": {\"$numberLong\": \"0\"}}, \"DatetimePositive\": {\"$date\": {\"$numberLong\": \"2147483647\"}}, \"DatetimeNegative\": {\"$date\": {\"$numberLong\": \"-2147483648\"}}, \"True\": true, \"False\": false, \"DBRef\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"57fd71e96e32ab4225b723fb\"}, \"$db\": \"database\"}, \"Minkey\": {\"$minKey\": 1}, \"Maxkey\": {\"$maxKey\": 1}, \"Null\": null}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/null.json000066400000000000000000000004021423026727100227200ustar00rootroot00000000000000{ "description": "Null type", "bson_type": "0x0A", "test_key": "a", "valid": [ { "description": "Null", "canonical_bson": "080000000A610000", "canonical_extjson": "{\"a\" : null}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/oid.json000066400000000000000000000016221423026727100225260ustar00rootroot00000000000000{ "description": "ObjectId", "bson_type": "0x07", "test_key": "a", "valid": [ { "description": "All zeroes", "canonical_bson": "1400000007610000000000000000000000000000", "canonical_extjson": "{\"a\" : {\"$oid\" : \"000000000000000000000000\"}}" }, { "description": "All ones", "canonical_bson": "14000000076100FFFFFFFFFFFFFFFFFFFFFFFF00", "canonical_extjson": "{\"a\" : {\"$oid\" : \"ffffffffffffffffffffffff\"}}" }, { "description": "Random", "canonical_bson": "1400000007610056E1FC72E0C917E9C471416100", "canonical_extjson": "{\"a\" : {\"$oid\" : \"56e1fc72e0c917e9c4714161\"}}" } ], "decodeErrors": [ { "description": "OID truncated", "bson": "1200000007610056E1FC72E0C917E9C471" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/regex.json000066400000000000000000000062011423026727100230630ustar00rootroot00000000000000{ "description": "Regular Expression type", "bson_type": "0x0B", "test_key": "a", "valid": [ { "description": "empty regex with no options", "canonical_bson": "0A0000000B6100000000", "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"\", \"options\" : \"\"}}}" }, { "description": "regex without options", "canonical_bson": "0D0000000B6100616263000000", "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"abc\", \"options\" : \"\"}}}" }, { "description": "regex with options", "canonical_bson": "0F0000000B610061626300696D0000", "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"abc\", \"options\" : \"im\"}}}" }, { "description": "regex with options (keys reversed)", "canonical_bson": "0F0000000B610061626300696D0000", "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"abc\", \"options\" : \"im\"}}}", "degenerate_extjson": "{\"a\" : {\"$regularExpression\" : {\"options\" : \"im\", \"pattern\": \"abc\"}}}" }, { "description": "regex with slash", "canonical_bson": "110000000B610061622F636400696D0000", "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"ab/cd\", \"options\" : \"im\"}}}" }, { "description": "flags not alphabetized", "degenerate_bson": "100000000B6100616263006D69780000", "canonical_bson": "100000000B610061626300696D780000", "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"abc\", \"options\" : \"imx\"}}}", "degenerate_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"abc\", \"options\" : \"mix\"}}}" }, { "description" : "Required escapes", "canonical_bson" : "100000000B610061625C226162000000", "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"ab\\\\\\\"ab\", \"options\" : \"\"}}}" }, { "description" : "Regular expression as value of $regex query operator", "canonical_bson" : "180000000B247265676578007061747465726E0069780000", "canonical_extjson": "{\"$regex\" : {\"$regularExpression\" : { \"pattern\": \"pattern\", \"options\" : \"ix\"}}}" }, { "description" : "Regular expression as value of $regex query operator with $options", "canonical_bson" : "270000000B247265676578007061747465726E000002246F7074696F6E73000300000069780000", "canonical_extjson": "{\"$regex\" : {\"$regularExpression\" : { \"pattern\": \"pattern\", \"options\" : \"\"}}, \"$options\" : \"ix\"}" } ], "decodeErrors": [ { "description": "Null byte in pattern string", "bson": "0F0000000B610061006300696D0000" }, { "description": "Null byte in flags string", "bson": "100000000B61006162630069006D0000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/string.json000066400000000000000000000053741423026727100232710ustar00rootroot00000000000000{ "description": "String", "bson_type": "0x02", "test_key": "a", "valid": [ { "description": "Empty string", "canonical_bson": "0D000000026100010000000000", "canonical_extjson": "{\"a\" : \"\"}" }, { "description": "Single character", "canonical_bson": "0E00000002610002000000620000", "canonical_extjson": "{\"a\" : \"b\"}" }, { "description": "Multi-character", "canonical_bson": "190000000261000D0000006162616261626162616261620000", "canonical_extjson": "{\"a\" : \"abababababab\"}" }, { "description": "two-byte UTF-8 (\u00e9)", "canonical_bson": "190000000261000D000000C3A9C3A9C3A9C3A9C3A9C3A90000", "canonical_extjson": "{\"a\" : \"\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\"}" }, { "description": "three-byte UTF-8 (\u2606)", "canonical_bson": "190000000261000D000000E29886E29886E29886E298860000", "canonical_extjson": "{\"a\" : \"\\u2606\\u2606\\u2606\\u2606\"}" }, { "description": "Embedded nulls", "canonical_bson": "190000000261000D0000006162006261620062616261620000", "canonical_extjson": "{\"a\" : \"ab\\u0000bab\\u0000babab\"}" }, { "description": "Required escapes", "canonical_bson" : "320000000261002600000061625C220102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F61620000", "canonical_extjson" : "{\"a\":\"ab\\\\\\\"\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001fab\"}" } ], "decodeErrors": [ { "description": "bad string length: 0 (but no 0x00 either)", "bson": "0C0000000261000000000000" }, { "description": "bad string length: -1", "bson": "0C000000026100FFFFFFFF00" }, { "description": "bad string length: eats terminator", "bson": "10000000026100050000006200620000" }, { "description": "bad string length: longer than rest of document", "bson": "120000000200FFFFFF00666F6F6261720000" }, { "description": "string is not null-terminated", "bson": "1000000002610004000000616263FF00" }, { "description": "empty string, but extra null", "bson": "0E00000002610001000000000000" }, { "description": "invalid UTF-8", "bson": "0E00000002610002000000E90000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/symbol.json000066400000000000000000000062401423026727100232610ustar00rootroot00000000000000{ "description": "Symbol", "bson_type": "0x0E", "deprecated": true, "test_key": "a", "valid": [ { "description": "Empty string", "canonical_bson": "0D0000000E6100010000000000", "canonical_extjson": "{\"a\": {\"$symbol\": \"\"}}", "converted_bson": "0D000000026100010000000000", "converted_extjson": "{\"a\": \"\"}" }, { "description": "Single character", "canonical_bson": "0E0000000E610002000000620000", "canonical_extjson": "{\"a\": {\"$symbol\": \"b\"}}", "converted_bson": "0E00000002610002000000620000", "converted_extjson": "{\"a\": \"b\"}" }, { "description": "Multi-character", "canonical_bson": "190000000E61000D0000006162616261626162616261620000", "canonical_extjson": "{\"a\": {\"$symbol\": \"abababababab\"}}", "converted_bson": "190000000261000D0000006162616261626162616261620000", "converted_extjson": "{\"a\": \"abababababab\"}" }, { "description": "two-byte UTF-8 (\u00e9)", "canonical_bson": "190000000E61000D000000C3A9C3A9C3A9C3A9C3A9C3A90000", "canonical_extjson": "{\"a\": {\"$symbol\": \"éééééé\"}}", "converted_bson": "190000000261000D000000C3A9C3A9C3A9C3A9C3A9C3A90000", "converted_extjson": "{\"a\": \"éééééé\"}" }, { "description": "three-byte UTF-8 (\u2606)", "canonical_bson": "190000000E61000D000000E29886E29886E29886E298860000", "canonical_extjson": "{\"a\": {\"$symbol\": \"☆☆☆☆\"}}", "converted_bson": "190000000261000D000000E29886E29886E29886E298860000", "converted_extjson": "{\"a\": \"☆☆☆☆\"}" }, { "description": "Embedded nulls", "canonical_bson": "190000000E61000D0000006162006261620062616261620000", "canonical_extjson": "{\"a\": {\"$symbol\": \"ab\\u0000bab\\u0000babab\"}}", "converted_bson": "190000000261000D0000006162006261620062616261620000", "converted_extjson": "{\"a\": \"ab\\u0000bab\\u0000babab\"}" } ], "decodeErrors": [ { "description": "bad symbol length: 0 (but no 0x00 either)", "bson": "0C0000000261000000000000" }, { "description": "bad symbol length: -1", "bson": "0C000000026100FFFFFFFF00" }, { "description": "bad symbol length: eats terminator", "bson": "10000000026100050000006200620000" }, { "description": "bad symbol length: longer than rest of document", "bson": "120000000200FFFFFF00666F6F6261720000" }, { "description": "symbol is not null-terminated", "bson": "1000000002610004000000616263FF00" }, { "description": "empty symbol, but extra null", "bson": "0E00000002610001000000000000" }, { "description": "invalid UTF-8", "bson": "0E00000002610002000000E90000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/timestamp.json000066400000000000000000000026651423026727100237660ustar00rootroot00000000000000{ "description": "Timestamp type", "bson_type": "0x11", "test_key": "a", "valid": [ { "description": "Timestamp: (123456789, 42)", "canonical_bson": "100000001161002A00000015CD5B0700", "canonical_extjson": "{\"a\" : {\"$timestamp\" : {\"t\" : 123456789, \"i\" : 42} } }" }, { "description": "Timestamp: (123456789, 42) (keys reversed)", "canonical_bson": "100000001161002A00000015CD5B0700", "canonical_extjson": "{\"a\" : {\"$timestamp\" : {\"t\" : 123456789, \"i\" : 42} } }", "degenerate_extjson": "{\"a\" : {\"$timestamp\" : {\"i\" : 42, \"t\" : 123456789} } }" }, { "description": "Timestamp with high-order bit set on both seconds and increment", "canonical_bson": "10000000116100FFFFFFFFFFFFFFFF00", "canonical_extjson": "{\"a\" : {\"$timestamp\" : {\"t\" : 4294967295, \"i\" : 4294967295} } }" }, { "description": "Timestamp with high-order bit set on both seconds and increment (not UINT32_MAX)", "canonical_bson": "1000000011610000286BEE00286BEE00", "canonical_extjson": "{\"a\" : {\"$timestamp\" : {\"t\" : 4000000000, \"i\" : 4000000000} } }" } ], "decodeErrors": [ { "description": "Truncated timestamp field", "bson": "0f0000001161002A00000015CD5B00" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/top.json000066400000000000000000000232221423026727100225550ustar00rootroot00000000000000{ "description": "Top-level document validity", "bson_type": "0x00", "valid": [ { "description": "Document with keys that start with $", "canonical_bson": "0F00000010246B6579002A00000000", "canonical_extjson": "{\"$key\": {\"$numberInt\": \"42\"}}" } ], "decodeErrors": [ { "description": "An object size that's too small to even include the object size, but is a well-formed, empty object", "bson": "0100000000" }, { "description": "An object size that's only enough for the object size, but is a well-formed, empty object", "bson": "0400000000" }, { "description": "One object, with length shorter than size (missing EOO)", "bson": "05000000" }, { "description": "One object, sized correctly, with a spot for an EOO, but the EOO is 0x01", "bson": "0500000001" }, { "description": "One object, sized correctly, with a spot for an EOO, but the EOO is 0xff", "bson": "05000000FF" }, { "description": "One object, sized correctly, with a spot for an EOO, but the EOO is 0x70", "bson": "0500000070" }, { "description": "Byte count is zero (with non-zero input length)", "bson": "00000000000000000000" }, { "description": "Stated length exceeds byte count, with truncated document", "bson": "1200000002666F6F0004000000626172" }, { "description": "Stated length exceeds byte count, with valid envelope", "bson": "1300000002666F6F00040000006261720000" }, { "description": "Stated length less than byte count, with valid envelope", "bson": "1100000002666F6F00040000006261720000" }, { "description": "Invalid BSON type low range", "bson": "07000000000000" }, { "description": "Invalid BSON type high range", "bson": "07000000800000" }, { "description": "Document truncated mid-key", "bson": "1200000002666F" }, { "description": "Null byte in document key", "bson": "0D000000107800000100000000" } ], "parseErrors": [ { "description" : "Bad $regularExpression (extra field)", "string" : "{\"a\" : {\"$regularExpression\": {\"pattern\": \"abc\", \"options\": \"\", \"unrelated\": true}}}" }, { "description" : "Bad $regularExpression (missing options field)", "string" : "{\"a\" : {\"$regularExpression\": {\"pattern\": \"abc\"}}}" }, { "description": "Bad $regularExpression (pattern is number, not string)", "string": "{\"x\" : {\"$regularExpression\" : { \"pattern\": 42, \"$options\" : \"\"}}}" }, { "description": "Bad $regularExpression (options are number, not string)", "string": "{\"x\" : {\"$regularExpression\" : { \"pattern\": \"a\", \"$options\" : 0}}}" }, { "description" : "Bad $regularExpression (missing pattern field)", "string" : "{\"a\" : {\"$regularExpression\": {\"options\":\"ix\"}}}" }, { "description": "Bad $oid (number, not string)", "string": "{\"a\" : {\"$oid\" : 42}}" }, { "description": "Bad $oid (extra field)", "string": "{\"a\" : {\"$oid\" : \"56e1fc72e0c917e9c4714161\", \"unrelated\": true}}" }, { "description": "Bad $numberInt (number, not string)", "string": "{\"a\" : {\"$numberInt\" : 42}}" }, { "description": "Bad $numberInt (extra field)", "string": "{\"a\" : {\"$numberInt\" : \"42\", \"unrelated\": true}}" }, { "description": "Bad $numberLong (number, not string)", "string": "{\"a\" : {\"$numberLong\" : 42}}" }, { "description": "Bad $numberLong (extra field)", "string": "{\"a\" : {\"$numberLong\" : \"42\", \"unrelated\": true}}" }, { "description": "Bad $numberDouble (number, not string)", "string": "{\"a\" : {\"$numberDouble\" : 42}}" }, { "description": "Bad $numberDouble (extra field)", "string": "{\"a\" : {\"$numberDouble\" : \".1\", \"unrelated\": true}}" }, { "description": "Bad $numberDecimal (number, not string)", "string": "{\"a\" : {\"$numberDecimal\" : 42}}" }, { "description": "Bad $numberDecimal (extra field)", "string": "{\"a\" : {\"$numberDecimal\" : \".1\", \"unrelated\": true}}" }, { "description": "Bad $binary (binary is number, not string)", "string": "{\"x\" : {\"$binary\" : {\"base64\" : 0, \"subType\" : \"00\"}}}" }, { "description": "Bad $binary (type is number, not string)", "string": "{\"x\" : {\"$binary\" : {\"base64\" : \"\", \"subType\" : 0}}}" }, { "description": "Bad $binary (missing $type)", "string": "{\"x\" : {\"$binary\" : {\"base64\" : \"//8=\"}}}" }, { "description": "Bad $binary (missing $binary)", "string": "{\"x\" : {\"$binary\" : {\"subType\" : \"00\"}}}" }, { "description": "Bad $binary (extra field)", "string": "{\"x\" : {\"$binary\" : {\"base64\" : \"//8=\", \"subType\" : 0, \"unrelated\": true}}}" }, { "description": "Bad $code (type is number, not string)", "string": "{\"a\" : {\"$code\" : 42}}" }, { "description": "Bad $code (type is number, not string) when $scope is also present", "string": "{\"a\" : {\"$code\" : 42, \"$scope\" : {}}}" }, { "description": "Bad $code (extra field)", "string": "{\"a\" : {\"$code\" : \"\", \"unrelated\": true}}" }, { "description": "Bad $code with $scope (scope is number, not doc)", "string": "{\"x\" : {\"$code\" : \"\", \"$scope\" : 42}}" }, { "description": "Bad $timestamp (type is number, not doc)", "string": "{\"a\" : {\"$timestamp\" : 42} }" }, { "description": "Bad $timestamp ('t' type is string, not number)", "string": "{\"a\" : {\"$timestamp\" : {\"t\" : \"123456789\", \"i\" : 42} } }" }, { "description": "Bad $timestamp ('i' type is string, not number)", "string": "{\"a\" : {\"$timestamp\" : {\"t\" : 123456789, \"i\" : \"42\"} } }" }, { "description": "Bad $timestamp (extra field at same level as $timestamp)", "string": "{\"a\" : {\"$timestamp\" : {\"t\" : \"123456789\", \"i\" : \"42\"}, \"unrelated\": true } }" }, { "description": "Bad $timestamp (extra field at same level as t and i)", "string": "{\"a\" : {\"$timestamp\" : {\"t\" : \"123456789\", \"i\" : \"42\", \"unrelated\": true} } }" }, { "description": "Bad $timestamp (missing t)", "string": "{\"a\" : {\"$timestamp\" : {\"i\" : \"42\"} } }" }, { "description": "Bad $timestamp (missing i)", "string": "{\"a\" : {\"$timestamp\" : {\"t\" : \"123456789\"} } }" }, { "description": "Bad $date (number, not string or hash)", "string": "{\"a\" : {\"$date\" : 42}}" }, { "description": "Bad $date (extra field)", "string": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"1356351330501\"}, \"unrelated\": true}}" }, { "description": "Bad $minKey (boolean, not integer)", "string": "{\"a\" : {\"$minKey\" : true}}" }, { "description": "Bad $minKey (wrong integer)", "string": "{\"a\" : {\"$minKey\" : 0}}" }, { "description": "Bad $minKey (extra field)", "string": "{\"a\" : {\"$minKey\" : 1, \"unrelated\": true}}" }, { "description": "Bad $maxKey (boolean, not integer)", "string": "{\"a\" : {\"$maxKey\" : true}}" }, { "description": "Bad $maxKey (wrong integer)", "string": "{\"a\" : {\"$maxKey\" : 0}}" }, { "description": "Bad $maxKey (extra field)", "string": "{\"a\" : {\"$maxKey\" : 1, \"unrelated\": true}}" }, { "description": "Bad DBpointer (extra field)", "string": "{\"a\": {\"$dbPointer\": {\"a\": {\"$numberInt\": \"1\"}, \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}, \"c\": {\"$numberInt\": \"2\"}, \"$ref\": \"b\"}}}" }, { "description" : "Null byte in document key", "string" : "{\"a\\u0000\": 1 }" }, { "description" : "Null byte in sub-document key", "string" : "{\"a\" : {\"b\\u0000\": 1 }}" }, { "description": "Null byte in $regularExpression pattern", "string": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"b\\u0000\", \"options\" : \"i\"}}}" }, { "description": "Null byte in $regularExpression options", "string": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"b\", \"options\" : \"i\\u0000\"}}}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus/undefined.json000066400000000000000000000006511423026727100237150ustar00rootroot00000000000000{ "description": "Undefined type (deprecated)", "bson_type": "0x06", "deprecated": true, "test_key": "a", "valid": [ { "description": "Undefined", "canonical_bson": "0800000006610000", "canonical_extjson": "{\"a\" : {\"$undefined\" : true}}", "converted_bson": "080000000A610000", "converted_extjson": "{\"a\" : null}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/000077500000000000000000000000001423026727100224035ustar00rootroot00000000000000bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/array.json000066400000000000000000000034211423026727100244140ustar00rootroot00000000000000{ "description": "Array", "bson_type": "0x04", "test_key": "a", "valid": [ { "description": "Empty", "bson": "0D000000046100050000000000", "extjson": "{\"a\" : []}" }, { "description": "Single Element Array", "bson": "140000000461000C0000001030000A0000000000", "extjson": "{\"a\" : [10]}" }, { "description": "Single Element Array with index set incorrectly to empty string", "bson": "130000000461000B00000010000A0000000000", "canonical_bson": "140000000461000C0000001030000A0000000000", "extjson": "{\"a\" : [10]}" }, { "description": "Single Element Array with index set incorrectly to ab", "bson": "150000000461000D000000106162000A0000000000", "canonical_bson": "140000000461000C0000001030000A0000000000", "extjson": "{\"a\" : [10]}" }, { "description": "Multi Element Array with duplicate indexes", "bson": "1b000000046100130000001030000a000000103000140000000000", "canonical_bson": "1b000000046100130000001030000a000000103100140000000000", "extjson": "{\"a\" : [10, 20]}" } ], "decodeErrors": [ { "description": "Array length too long: eats outer terminator", "bson": "140000000461000D0000001030000A0000000000" }, { "description": "Array length too short: leaks terminator", "bson": "140000000461000B0000001030000A0000000000" }, { "description": "Invalid Array: bad string length in field", "bson": "1A00000004666F6F00100000000230000500000062617A000000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/binary.json000066400000000000000000000050231423026727100245620ustar00rootroot00000000000000{ "description": "Binary type", "bson_type": "0x05", "test_key": "x", "valid": [ { "description": "subtype 0x00 (Zero-length)", "bson": "0D000000057800000000000000", "extjson": "{\"x\" : {\"$binary\" : \"\", \"$type\" : \"00\"}}" }, { "description": "subtype 0x00", "bson": "0F0000000578000200000000FFFF00", "extjson": "{\"x\" : {\"$binary\" : \"//8=\", \"$type\" : \"00\"}}" }, { "description": "subtype 0x01", "bson": "0F0000000578000200000001FFFF00", "extjson": "{\"x\" : {\"$binary\" : \"//8=\", \"$type\" : \"01\"}}" }, { "description": "subtype 0x02", "bson": "13000000057800060000000202000000ffff00", "extjson": "{\"x\" : {\"$binary\" : \"//8=\", \"$type\" : \"02\"}}" }, { "description": "subtype 0x03", "bson": "1D000000057800100000000373FFD26444B34C6990E8E7D1DFC035D400", "extjson": "{\"x\" : {\"$binary\" : \"c//SZESzTGmQ6OfR38A11A==\", \"$type\" : \"03\"}}" }, { "description": "subtype 0x04", "bson": "1D000000057800100000000473FFD26444B34C6990E8E7D1DFC035D400", "extjson": "{\"x\" : {\"$binary\" : \"c//SZESzTGmQ6OfR38A11A==\", \"$type\" : \"04\"}}" }, { "description": "subtype 0x05", "bson": "1D000000057800100000000573FFD26444B34C6990E8E7D1DFC035D400", "extjson": "{\"x\" : {\"$binary\" : \"c//SZESzTGmQ6OfR38A11A==\", \"$type\" : \"05\"}}" }, { "description": "subtype 0x80", "bson": "0F0000000578000200000080FFFF00", "extjson": "{\"x\" : {\"$binary\" : \"//8=\", \"$type\" : \"80\"}}" } ], "decodeErrors": [ { "description": "Length longer than document", "bson": "1D000000057800FF0000000573FFD26444B34C6990E8E7D1DFC035D400" }, { "description": "Negative length", "bson": "0D000000057800FFFFFFFF0000" }, { "description": "subtype 0x02 length too long ", "bson": "13000000057800060000000203000000FFFF00" }, { "description": "subtype 0x02 length too short", "bson": "13000000057800060000000201000000FFFF00" }, { "description": "subtype 0x02 length negative one", "bson": "130000000578000600000002FFFFFFFFFFFF00" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/boolean.json000066400000000000000000000012051423026727100247130ustar00rootroot00000000000000{ "description": "Boolean", "bson_type": "0x08", "test_key": "b", "valid": [ { "description": "True", "bson": "090000000862000100", "extjson": "{\"b\" : true}" }, { "description": "False", "bson": "090000000862000000", "extjson": "{\"b\" : false}" } ], "decodeErrors": [ { "description": "Invalid boolean value of 2", "bson": "090000000862000200" }, { "description": "Invalid boolean value of -1", "bson": "09000000086200FF00" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/code.json000066400000000000000000000043751423026727100242210ustar00rootroot00000000000000{ "description": "Code", "bson_type": "0x0D", "test_key": "a", "valid": [ { "description": "Empty string", "bson": "0D0000000D6100010000000000", "extjson": "{\"a\" : {\"$code\" : \"\"}}" }, { "description": "Single character", "bson": "0E0000000D610002000000620000", "extjson": "{\"a\" : {\"$code\" : \"b\"}}" }, { "description": "Multi-character", "bson": "190000000D61000D0000006162616261626162616261620000", "extjson": "{\"a\" : {\"$code\" : \"abababababab\"}}" }, { "description": "two-byte UTF-8 (\u00e9)", "bson": "190000000261000D000000C3A9C3A9C3A9C3A9C3A9C3A90000", "extjson": "{\"a\" : \"\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\"}" }, { "description": "three-byte UTF-8 (\u2606)", "bson": "190000000261000D000000E29886E29886E29886E298860000", "extjson": "{\"a\" : \"\\u2606\\u2606\\u2606\\u2606\"}" }, { "description": "Embedded nulls", "bson": "190000000261000D0000006162006261620062616261620000", "extjson": "{\"a\" : \"ab\\u0000bab\\u0000babab\"}" } ], "decodeErrors": [ { "description": "bad code string length: 0 (but no 0x00 either)", "bson": "0C0000000261000000000000" }, { "description": "bad code string length: -1", "bson": "0C000000026100FFFFFFFF00" }, { "description": "bad code string length: eats terminator", "bson": "10000000026100050000006200620000" }, { "description": "bad code string length: longer than rest of document", "bson": "120000000200FFFFFF00666F6F6261720000" }, { "description": "code string is not null-terminated", "bson": "1000000002610004000000616263FF00" }, { "description": "empty code string, but extra null", "bson": "0E00000002610001000000000000" }, { "description": "invalid UTF-8", "bson": "0E00000002610002000000E90000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/code_w_scope.json000066400000000000000000000065371423026727100257420ustar00rootroot00000000000000{ "description": "CodeWithScope", "bson_type": "0x0F", "test_key": "a", "valid": [ { "description": "Empty code string, empty scope", "bson": "160000000F61000E0000000100000000050000000000", "extjson": "{\"a\" : {\"$code\" : \"\", \"$scope\" : {}}}" }, { "description": "Non-empty code string, empty scope", "bson": "1A0000000F610012000000050000006162636400050000000000", "extjson": "{\"a\" : {\"$code\" : \"abcd\", \"$scope\" : {}}}" }, { "description": "Empty code string, non-empty scope", "bson": "1D0000000F61001500000001000000000C000000107800010000000000", "extjson": "{\"a\" : {\"$code\" : \"\", \"$scope\" : {\"x\" : 1}}}" }, { "description": "Non-empty code string and non-empty scope", "bson": "210000000F6100190000000500000061626364000C000000107800010000000000", "extjson": "{\"a\" : {\"$code\" : \"abcd\", \"$scope\" : {\"x\" : 1}}}" }, { "description": "Unicode and embedded null in code string, empty scope", "bson": "1A0000000F61001200000005000000C3A9006400050000000000", "extjson": "{\"a\" : {\"$code\" : \"\\u00e9\\u0000d\", \"$scope\" : {}}}" } ], "decodeErrors": [ { "description": "field length zero", "bson": "280000000F6100000000000500000061626364001300000010780001000000107900010000000000" }, { "description": "field length negative", "bson": "280000000F6100FFFFFFFF0500000061626364001300000010780001000000107900010000000000" }, { "description": "field length too short (less than minimum size)", "bson": "160000000F61000D0000000100000000050000000000" }, { "description": "field length too short (truncates scope)", "bson": "280000000F61001F0000000500000061626364001300000010780001000000107900010000000000" }, { "description": "field length too long (clips outer doc)", "bson": "280000000F6100210000000500000061626364001300000010780001000000107900010000000000" }, { "description": "field length too long (longer than outer doc)", "bson": "280000000F6100FF0000000500000061626364001300000010780001000000107900010000000000" }, { "description": "bad code string: length too short", "bson": "280000000F6100200000000400000061626364001300000010780001000000107900010000000000" }, { "description": "bad code string: length too long (clips scope)", "bson": "280000000F6100200000000600000061626364001300000010780001000000107900010000000000" }, { "description": "bad code string: negative length", "bson": "280000000F610020000000FFFFFFFF61626364001300000010780001000000107900010000000000" }, { "description": "bad code string: length longer than field", "bson": "280000000F610020000000FF00000061626364001300000010780001000000107900010000000000" }, { "description": "bad scope doc (field has bad string length)", "bson": "1C0000000F001500000001000000000C000000020000000000000000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/document.json000066400000000000000000000022401423026727100251120ustar00rootroot00000000000000{ "description": "Document", "bson_type": "0x03", "test_key": "x", "valid": [ { "description": "Empty subdoc", "bson": "0D000000037800050000000000", "extjson": "{\"x\" : {}}" }, { "description": "Empty-string key subdoc", "bson": "150000000378000D00000002000200000062000000", "extjson": "{\"x\" : {\"\" : \"b\"}}" }, { "description": "Single-character key subdoc", "bson": "160000000378000E0000000261000200000062000000", "extjson": "{\"x\" : {\"a\" : \"b\"}}" } ], "decodeErrors": [ { "description": "Subdocument length too long: eats outer terminator", "bson": "1800000003666F6F000F0000001062617200FFFFFF7F0000" }, { "description": "Subdocument length too short: leaks terminator", "bson": "1500000003666F6F000A0000000862617200010000" }, { "description": "Invalid subdocument: bad string length in field", "bson": "1C00000003666F6F001200000002626172000500000062617A000000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/double.json000066400000000000000000000037361423026727100245610ustar00rootroot00000000000000{ "description": "Float", "bson_type": "0x01", "test_key": "d", "valid": [ { "description": "+1.0", "bson": "10000000016400000000000000F03F00", "extjson": "{\"d\" : 1.0}" }, { "description": "-1.0", "bson": "10000000016400000000000000F0BF00", "extjson": "{\"d\" : -1.0}" }, { "description": "+1.0001220703125", "bson": "10000000016400000000008000F03F00", "extjson": "{\"d\" : 1.0001220703125}" }, { "description": "-1.0001220703125", "bson": "10000000016400000000008000F0BF00", "extjson": "{\"d\" : -1.0001220703125}" }, { "description": "+2.0001220703125e10", "bson": "1000000001640000807ca1a9a0124200", "extjson": "{\"d\" : 2.0001220703125e10}" }, { "description": "-2.0001220703125e10", "bson": "1000000001640000807ca1a9a012c200", "extjson": "{\"d\" : -2.0001220703125e10}" }, { "description": "0.0", "bson": "10000000016400000000000000000000", "extjson": "{\"d\" : 0.0}" }, { "description": "-0.0", "bson": "10000000016400000000000000008000", "extjson": "{\"d\" : -0.0}" }, { "description": "NaN", "bson": "10000000016400000000000000F87F00" }, { "description": "NaN with payload", "bson": "10000000016400120000000000F87F00" }, { "description": "Inf", "bson": "10000000016400000000000000F07F00" }, { "description": "-Inf", "bson": "10000000016400000000000000F0FF00" } ], "decodeErrors": [ { "description": "double truncated", "bson": "0B0000000164000000F03F00" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/failures/000077500000000000000000000000001423026727100242155ustar00rootroot00000000000000bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/failures/datetime.json000066400000000000000000000021341423026727100267040ustar00rootroot00000000000000{ "description": "DateTime", "bson_type": "0x09", "test_key": "a", "valid": [ { "description": "epoch", "bson": "10000000096100000000000000000000", "extjson": "{\"a\" : {\"$date\" : \"1970-01-01T00:00:00.000Z\"}}", "canonical_extjson": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"0\"}}}" }, { "description": "positive ms", "bson": "10000000096100C4D8D6CC3B01000000", "extjson": "{\"a\" : {\"$date\" : \"2012-12-24T12:15:30.500Z\"}}", "canonical_extjson": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"1356351330500\"}}}" }, { "description": "negative", "bson": "10000000096100C43CE7B9BDFFFFFF00", "extjson": "{\"a\" : {\"$date\" : \"1960-12-24T12:15:30.500Z\"}}", "canonical_extjson": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"-284643869500\"}}}" } ], "decodeErrors": [ { "description": "datetime field truncated", "bson": "0C0000000961001234567800" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/failures/dbpointer.json000066400000000000000000000025701423026727100271020ustar00rootroot00000000000000{ "description": "DBPointer type (deprecated)", "bson_type": "0x0C", "deprecated": true, "test_key": "a", "valid": [ { "description": "DBpointer", "bson": "1A0000000C610002000000620056E1FC72E0C917E9C471416100" }, { "description": "With two-byte UTF-8", "bson": "1B0000000C610003000000C3A90056E1FC72E0C917E9C471416100" } ], "decodeErrors": [ { "description": "String with negative length", "bson": "1A0000000C6100FFFFFFFF620056E1FC72E0C917E9C471416100" }, { "description": "String with zero length", "bson": "1A0000000C610000000000620056E1FC72E0C917E9C471416100" }, { "description": "String not null terminated", "bson": "1A0000000C610002000000626256E1FC72E0C917E9C471416100" }, { "description": "short OID (less than minimum length for field)", "bson": "160000000C61000300000061620056E1FC72E0C91700" }, { "description": "short OID (greater than minimum, but truncated)", "bson": "1A0000000C61000300000061620056E1FC72E0C917E9C4716100" }, { "description": "String with bad UTF-8", "bson": "1A0000000C610002000000E90056E1FC72E0C917E9C471416100" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/failures/int64.json000066400000000000000000000022021423026727100260500ustar00rootroot00000000000000{ "description": "Int64 type", "bson_type": "0x12", "test_key": "a", "valid": [ { "description": "MinValue", "bson": "10000000126100000000000000008000", "extjson": "{\"a\" : {\"$numberLong\" : \"-9223372036854775808\"}}" }, { "description": "MaxValue", "bson": "10000000126100FFFFFFFFFFFFFF7F00", "extjson": "{\"a\" : {\"$numberLong\" : \"9223372036854775807\"}}" }, { "description": "-1", "bson": "10000000126100FFFFFFFFFFFFFFFF00", "extjson": "{\"a\" : {\"$numberLong\" : \"-1\"}}" }, { "description": "0", "bson": "10000000126100000000000000000000", "extjson": "{\"a\" : {\"$numberLong\" : \"0\"}}" }, { "description": "1", "bson": "10000000126100010000000000000000", "extjson": "{\"a\" : {\"$numberLong\" : \"1\"}}" } ], "decodeErrors": [ { "description": "int64 field truncated", "bson": "0C0000001261001234567800" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/failures/symbol.json000066400000000000000000000035561423026727100264260ustar00rootroot00000000000000{ "description": "Symbol", "bson_type": "0x0E", "deprecated": true, "test_key": "a", "valid": [ { "description": "Empty string", "bson": "0D0000000E6100010000000000" }, { "description": "Single character", "bson": "0E0000000E610002000000620000" }, { "description": "Multi-character", "bson": "190000000E61000D0000006162616261626162616261620000" }, { "description": "two-byte UTF-8 (\u00e9)", "bson": "190000000E61000D000000C3A9C3A9C3A9C3A9C3A9C3A90000" }, { "description": "three-byte UTF-8 (\u2606)", "bson": "190000000E61000D000000E29886E29886E29886E298860000" }, { "description": "Embedded nulls", "bson": "190000000E61000D0000006162006261620062616261620000" } ], "decodeErrors": [ { "description": "bad symbol length: 0 (but no 0x00 either)", "bson": "0C0000000261000000000000" }, { "description": "bad symbol length: -1", "bson": "0C000000026100FFFFFFFF00" }, { "description": "bad symbol length: eats terminator", "bson": "10000000026100050000006200620000" }, { "description": "bad symbol length: longer than rest of document", "bson": "120000000200FFFFFF00666F6F6261720000" }, { "description": "symbol is not null-terminated", "bson": "1000000002610004000000616263FF00" }, { "description": "empty symbol, but extra null", "bson": "0E00000002610001000000000000" }, { "description": "invalid UTF-8", "bson": "0E00000002610002000000E90000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/int32.json000066400000000000000000000017101423026727100242340ustar00rootroot00000000000000{ "description": "Integer", "bson_type": "0x10", "test_key": "i", "valid": [ { "description": "MinValue", "bson": "0C0000001069000000008000", "extjson": "{\"i\" : -2147483648}" }, { "description": "MaxValue", "bson": "0C000000106900FFFFFF7F00", "extjson": "{\"i\" : 2147483647}" }, { "description": "-1", "bson": "0C000000106900FFFFFFFF00", "extjson": "{\"i\" : -1}" }, { "description": "0", "bson": "0C0000001069000000000000", "extjson": "{\"i\" : 0}" }, { "description": "1", "bson": "0C0000001069000100000000", "extjson": "{\"i\" : 1}" } ], "decodeErrors": [ { "description": "Bad int32 field length", "bson": "090000001061000500" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/maxkey.json000066400000000000000000000003721423026727100245760ustar00rootroot00000000000000{ "description": "MaxKey", "bson_type": "0xFF", "test_key": "a", "valid": [ { "description": "Maxkey", "bson": "080000007F610000", "extjson": "{\"a\" : {\"$maxKey\" : 1}}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/minkey.json000066400000000000000000000003721423026727100245740ustar00rootroot00000000000000{ "description": "MinKey", "bson_type": "0xFF", "test_key": "a", "valid": [ { "description": "Minkey", "bson": "08000000FF610000", "extjson": "{\"a\" : {\"$minKey\" : 1}}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/null.json000066400000000000000000000003551423026727100242530ustar00rootroot00000000000000{ "description": "NilClass", "bson_type": "0x0A", "test_key": "a", "valid": [ { "description": "Null", "bson": "080000000A610000", "extjson": "{\"a\" : null}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/oid.json000066400000000000000000000015261423026727100240550ustar00rootroot00000000000000{ "description": "ObjectId", "bson_type": "0x07", "test_key": "a", "valid": [ { "description": "All zeroes", "bson": "1400000007610000000000000000000000000000", "extjson": "{\"a\" : {\"$oid\" : \"000000000000000000000000\"}}" }, { "description": "All ones", "bson": "14000000076100FFFFFFFFFFFFFFFFFFFFFFFF00", "extjson": "{\"a\" : {\"$oid\" : \"ffffffffffffffffffffffff\"}}" }, { "description": "Random", "bson": "1400000007610056E1FC72E0C917E9C471416100", "extjson": "{\"a\" : {\"$oid\" : \"56e1fc72e0c917e9c4714161\"}}" } ], "decodeErrors": [ { "description": "OID truncated", "bson": "1200000007610056E1FC72E0C917E9C471" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/regex.json000066400000000000000000000022601423026727100244100ustar00rootroot00000000000000{ "description": "Regexp", "bson_type": "0x0B", "test_key": "a", "valid": [ { "description": "empty regex with no options", "bson": "0A0000000B6100000000", "extjson": "{\"a\" : {\"$regex\" : \"\", \"$options\" : \"\"}}" }, { "description": "regex without options", "bson": "0D0000000B6100616263000000", "extjson": "{\"a\" : {\"$regex\" : \"abc\", \"$options\" : \"\"}}" }, { "description": "regex with options", "bson": "0F0000000B610061626300696D0000", "extjson": "{\"a\" : {\"$regex\" : \"abc\", \"$options\" : \"im\"}}" }, { "description": "regex with slash", "bson": "110000000B610061622F636400696D0000", "extjson": "{\"a\" : {\"$regex\" : \"ab/cd\", \"$options\" : \"im\"}}" } ], "decodeErrors": [ { "description": "embedded null in pattern", "bson": "0F0000000B610061006300696D0000" }, { "description": "embedded null in flags", "bson": "100000000B61006162630069006D0000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/string.json000066400000000000000000000042671423026727100246150ustar00rootroot00000000000000{ "description": "String", "bson_type": "0x02", "test_key": "a", "valid": [ { "description": "Empty string", "bson": "0D000000026100010000000000", "extjson": "{\"a\" : \"\"}" }, { "description": "Single character", "bson": "0E00000002610002000000620000", "extjson": "{\"a\" : \"b\"}" }, { "description": "Multi-character", "bson": "190000000261000D0000006162616261626162616261620000", "extjson": "{\"a\" : \"abababababab\"}" }, { "description": "two-byte UTF-8 (\u00e9)", "bson": "190000000261000D000000C3A9C3A9C3A9C3A9C3A9C3A90000", "extjson": "{\"a\" : \"\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\"}" }, { "description": "three-byte UTF-8 (\u2606)", "bson": "190000000261000D000000E29886E29886E29886E298860000", "extjson": "{\"a\" : \"\\u2606\\u2606\\u2606\\u2606\"}" }, { "description": "Embedded nulls", "bson": "190000000261000D0000006162006261620062616261620000", "extjson": "{\"a\" : \"ab\\u0000bab\\u0000babab\"}" } ], "decodeErrors": [ { "description": "bad string length: 0 (but no 0x00 either)", "bson": "0C0000000261000000000000" }, { "description": "bad string length: -1", "bson": "0C000000026100FFFFFFFF00" }, { "description": "bad string length: eats terminator", "bson": "10000000026100050000006200620000" }, { "description": "bad string length: longer than rest of document", "bson": "120000000200FFFFFF00666F6F6261720000" }, { "description": "string is not null-terminated", "bson": "1000000002610004000000616263FF00" }, { "description": "empty string, but extra null", "bson": "0E00000002610001000000000000" }, { "description": "invalid UTF-8", "bson": "0E00000002610002000000E90000" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/timestamp.json000066400000000000000000000007401423026727100253020ustar00rootroot00000000000000{ "description": "Timestamp", "bson_type": "0x11", "test_key": "a", "valid": [ { "description": "Timestamp: (123456789, 42)", "bson": "100000001161002A00000015CD5B0700", "extjson": "{\"a\" : {\"$timestamp\" : {\"t\" : 123456789, \"i\" : 42}}}" } ], "decodeErrors": [ { "description": "Truncated timestamp field", "bson": "0f0000001161002A00000015CD5B00" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/top.json000066400000000000000000000042771423026727100241120ustar00rootroot00000000000000{ "description": "Top-level document validity", "bson_type": "0x00", "decodeErrors": [ { "description": "An object size that's too small to even include the object size, but is a well-formed, empty object", "bson": "0100000000" }, { "description": "An object size that's only enough for the object size, but is a well-formed, empty object", "bson": "0400000000" }, { "description": "One object, with length shorter than size (missing EOO)", "bson": "05000000" }, { "description": "One object, sized correctly, with a spot for an EOO, but the EOO is 0x01", "bson": "0500000001" }, { "description": "One object, sized correctly, with a spot for an EOO, but the EOO is 0xff", "bson": "05000000FF" }, { "description": "One object, sized correctly, with a spot for an EOO, but the EOO is 0x70", "bson": "0500000070" }, { "description": "Byte count is zero (with non-zero input length)", "bson": "00000000000000000000" }, { "description": "Stated length exceeds byte count, with truncated document", "bson": "1200000002666F6F0004000000626172" }, { "description": "Stated length less than byte count, with garbage after envelope", "bson": "1200000002666F6F00040000006261720000DEADBEEF" }, { "description": "Stated length exceeds byte count, with valid envelope", "bson": "1300000002666F6F00040000006261720000" }, { "description": "Stated length less than byte count, with valid envelope", "bson": "1100000002666F6F00040000006261720000" }, { "description": "Invalid BSON type low range", "bson": "07000000000000" }, { "description": "Invalid BSON type high range", "bson": "07000000800000" }, { "description": "Document truncated mid-key", "bson": "1200000002666F" } ] } bson-ruby-4.15.0/spec/spec_tests/data/corpus_legacy/undefined.json000066400000000000000000000004601423026727100252370ustar00rootroot00000000000000{ "description": "Undefined type (deprecated)", "bson_type": "0x06", "deprecated": true, "test_key": "a", "valid": [ { "description": "Undefined", "bson": "0800000006610000", "extjson": "{\"a\" : {\"$undefined\" : true}}" } ] } bson-ruby-4.15.0/spec/spec_tests/data/decimal128/000077500000000000000000000000001423026727100213755ustar00rootroot00000000000000bson-ruby-4.15.0/spec/spec_tests/data/decimal128/decimal128-1.json000066400000000000000000000422331423026727100242630ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "valid": [ { "description": "Special - Canonical NaN", "subject": "180000001364000000000000000000000000000000007C00", "string": "NaN", "extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}" }, { "description": "Special - Negative NaN", "subject": "18000000136400000000000000000000000000000000FC00", "string": "NaN", "from_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}" }, { "description": "Special - Canonical SNaN", "subject": "180000001364000000000000000000000000000000007E00", "string": "NaN", "from_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}" }, { "description": "Special - Negative SNaN", "subject": "18000000136400000000000000000000000000000000FE00", "string": "NaN", "from_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}" }, { "description": "Special - NaN with a payload", "subject": "180000001364001200000000000000000000000000007E00", "string": "NaN", "from_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}" }, { "description": "Special - Canonical Positive Infinity", "subject": "180000001364000000000000000000000000000000007800", "string": "Infinity", "extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" }, { "description": "Special - Canonical Negative Infinity", "subject": "18000000136400000000000000000000000000000000F800", "string": "-Infinity", "extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" }, { "description": "Special - Invalid representation treated as 0", "subject": "180000001364000000000000000000000000000000106C00", "string": "0", "from_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "Special - Invalid representation treated as -0", "subject": "18000000136400DCBA9876543210DEADBEEF00000010EC00", "string": "-0", "from_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" }, { "description": "Special - Invalid representation treated as 0E3", "subject": "18000000136400FFFFFFFFFFFFFFFFFFFFFFFFFFFF116C00", "string": "0E+3", "from_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}" }, { "description": "Regular - Adjusted Exponent Limit", "subject": "18000000136400F2AF967ED05C82DE3297FF6FDE3CF22F00", "string": "0.000001234567890123456789012345678901234", "extjson": "{\"d\": { \"$numberDecimal\": \"0.000001234567890123456789012345678901234\" }}" }, { "description": "Regular - Smallest", "subject": "18000000136400D204000000000000000000000000343000", "string": "0.001234", "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.001234\"}}" }, { "description": "Regular - Smallest with Trailing Zeros", "subject": "1800000013640040EF5A07000000000000000000002A3000", "string": "0.00123400000", "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00123400000\"}}" }, { "description": "Regular - 0.1", "subject": "1800000013640001000000000000000000000000003E3000", "string": "0.1", "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1\"}}" }, { "description": "Regular - 0.1234567890123456789012345678901234", "subject": "18000000136400F2AF967ED05C82DE3297FF6FDE3CFC2F00", "string": "0.1234567890123456789012345678901234", "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1234567890123456789012345678901234\"}}" }, { "description": "Regular - 0", "subject": "180000001364000000000000000000000000000000403000", "string": "0", "extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" }, { "description": "Regular - -0", "subject": "18000000136400000000000000000000000000000040B000", "string": "-0", "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" }, { "description": "Regular - -0.0", "subject": "1800000013640000000000000000000000000000003EB000", "string": "-0.0", "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0\"}}" }, { "description": "Regular - 2", "subject": "180000001364000200000000000000000000000000403000", "string": "2", "extjson": "{\"d\" : {\"$numberDecimal\" : \"2\"}}" }, { "description": "Regular - 2.000", "subject": "18000000136400D0070000000000000000000000003A3000", "string": "2.000", "extjson": "{\"d\" : {\"$numberDecimal\" : \"2.000\"}}" }, { "description": "Regular - Largest", "subject": "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000", "string": "1234567890123456789012345678901234", "extjson": "{\"d\" : {\"$numberDecimal\" : \"1234567890123456789012345678901234\"}}" }, { "description": "Scientific - Tiniest", "subject": "18000000136400FFFFFFFF638E8D37C087ADBE09ED010000", "string": "9.999999999999999999999999999999999E-6143", "extjson": "{\"d\" : {\"$numberDecimal\" : \"9.999999999999999999999999999999999E-6143\"}}" }, { "description": "Scientific - Tiny", "subject": "180000001364000100000000000000000000000000000000", "string": "1E-6176", "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}" }, { "description": "Scientific - Negative Tiny", "subject": "180000001364000100000000000000000000000000008000", "string": "-1E-6176", "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6176\"}}" }, { "description": "Scientific - Adjusted Exponent Limit", "subject": "18000000136400F2AF967ED05C82DE3297FF6FDE3CF02F00", "string": "1.234567890123456789012345678901234E-7", "extjson": "{\"d\": { \"$numberDecimal\": \"1.234567890123456789012345678901234E-7\" }}" }, { "description": "Scientific - Fractional", "subject": "1800000013640064000000000000000000000000002CB000", "string": "-1.00E-8", "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.00E-8\"}}" }, { "description": "Scientific - 0 with Exponent", "subject": "180000001364000000000000000000000000000000205F00", "string": "0E+6000", "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6000\"}}" }, { "description": "Scientific - 0 with Negative Exponent", "subject": "1800000013640000000000000000000000000000007A2B00", "string": "0E-611", "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-611\"}}" }, { "description": "Scientific - No Decimal with Signed Exponent", "subject": "180000001364000100000000000000000000000000463000", "string": "1E+3", "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+3\"}}" }, { "description": "Scientific - Trailing Zero", "subject": "180000001364001A04000000000000000000000000423000", "string": "1.050E+4", "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.050E+4\"}}" }, { "description": "Scientific - With Decimal", "subject": "180000001364006900000000000000000000000000423000", "string": "1.05E+3", "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.05E+3\"}}" }, { "description": "Scientific - Full", "subject": "18000000136400FFFFFFFFFFFFFFFFFFFFFFFFFFFF403000", "string": "5192296858534827628530496329220095", "extjson": "{\"d\" : {\"$numberDecimal\" : \"5192296858534827628530496329220095\"}}" }, { "description": "Scientific - Large", "subject": "18000000136400000000000A5BC138938D44C64D31FE5F00", "string": "1.000000000000000000000000000000000E+6144", "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}" }, { "description": "Scientific - Largest", "subject": "18000000136400FFFFFFFF638E8D37C087ADBE09EDFF5F00", "string": "9.999999999999999999999999999999999E+6144", "extjson": "{\"d\" : {\"$numberDecimal\" : \"9.999999999999999999999999999999999E+6144\"}}" }, { "description": "Non-Canonical Parsing - Exponent Normalization", "subject": "1800000013640064000000000000000000000000002CB000", "string": "-1.00E-8", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"-100E-10\"}}" }, { "description": "Non-Canonical Parsing - Unsigned Positive Exponent", "subject": "180000001364000100000000000000000000000000463000", "string": "1E+3", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E3\"}}" }, { "description": "Non-Canonical Parsing - Lowercase Exponent Identifier", "subject": "180000001364000100000000000000000000000000463000", "string": "1E+3", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"1e+3\"}}" }, { "description": "Non-Canonical Parsing - Long Significand with Exponent", "subject": "1800000013640079D9E0F9763ADA429D0200000000583000", "string": "1.2345689012345789012345E+34", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"12345689012345789012345E+12\"}}" }, { "description": "Non-Canonical Parsing - Positive Sign", "subject": "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000", "string": "1234567890123456789012345678901234", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"+1234567890123456789012345678901234\"}}" }, { "description": "Non-Canonical Parsing - Long Decimal String", "subject": "180000001364000100000000000000000000000000722800", "string": "1E-999", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \".000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001\"}}" }, { "description": "Non-Canonical Parsing - nan", "subject": "180000001364000000000000000000000000000000007C00", "string": "NaN", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"nan\"}}" }, { "description": "Non-Canonical Parsing - nAn", "subject": "180000001364000000000000000000000000000000007C00", "string": "NaN", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"nAn\"}}" }, { "description": "Non-Canonical Parsing - +infinity", "subject": "180000001364000000000000000000000000000000007800", "string": "Infinity", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"+infinity\"}}" }, { "description": "Non-Canonical Parsing - infinity", "subject": "180000001364000000000000000000000000000000007800", "string": "Infinity", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"infinity\"}}" }, { "description": "Non-Canonical Parsing - infiniTY", "subject": "180000001364000000000000000000000000000000007800", "string": "Infinity", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"infiniTY\"}}" }, { "description": "Non-Canonical Parsing - inf", "subject": "180000001364000000000000000000000000000000007800", "string": "Infinity", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"inf\"}}" }, { "description": "Non-Canonical Parsing - inF", "subject": "180000001364000000000000000000000000000000007800", "string": "Infinity", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"inF\"}}" }, { "description": "Non-Canonical Parsing - -infinity", "subject": "18000000136400000000000000000000000000000000F800", "string": "-Infinity", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"-infinity\"}}" }, { "description": "Non-Canonical Parsing - -infiniTy", "subject": "18000000136400000000000000000000000000000000F800", "string": "-Infinity", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"-infiniTy\"}}" }, { "description": "Non-Canonical Parsing - -Inf", "subject": "18000000136400000000000000000000000000000000F800", "string": "-Infinity", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" }, { "description": "Non-Canonical Parsing - -inf", "subject": "18000000136400000000000000000000000000000000F800", "string": "-Infinity", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"-inf\"}}" }, { "description": "Non-Canonical Parsing - -inF", "subject": "18000000136400000000000000000000000000000000F800", "string": "-Infinity", "to_extjson": false, "extjson": "{\"d\" : {\"$numberDecimal\" : \"-inF\"}}" }, { "description": "Rounded Subnormal number", "subject": "180000001364000100000000000000000000000000000000", "string": "10E-6177", "match_string": "1E-6176" }, { "description": "Clamped", "subject": "180000001364000a00000000000000000000000000fe5f00", "string": "1E6112", "match_string": "1.0E+6112" }, { "description": "Exact rounding", "subject": "18000000136400000000000a5bc138938d44c64d31cc3700", "string": "1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "match_string": "1.000000000000000000000000000000000E+999" } ] } bson-ruby-4.15.0/spec/spec_tests/data/decimal128/decimal128-2.json000066400000000000000000000727051423026727100242730ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "valid": [ { "description": "[decq021] Normality", "subject": "18000000136400F2AF967ED05C82DE3297FF6FDE3C40B000", "string": "-1234567890123456789012345678901234" }, { "description": "[decq823] values around [u]int32 edges (zeros done earlier)", "subject": "18000000136400010000800000000000000000000040B000", "string": "-2147483649" }, { "description": "[decq822] values around [u]int32 edges (zeros done earlier)", "subject": "18000000136400000000800000000000000000000040B000", "string": "-2147483648" }, { "description": "[decq821] values around [u]int32 edges (zeros done earlier)", "subject": "18000000136400FFFFFF7F0000000000000000000040B000", "string": "-2147483647" }, { "description": "[decq820] values around [u]int32 edges (zeros done earlier)", "subject": "18000000136400FEFFFF7F0000000000000000000040B000", "string": "-2147483646" }, { "description": "[decq152] fold-downs (more below)", "subject": "18000000136400393000000000000000000000000040B000", "string": "-12345" }, { "description": "[decq154] fold-downs (more below)", "subject": "18000000136400D20400000000000000000000000040B000", "string": "-1234" }, { "description": "[decq006] derivative canonical plain strings", "subject": "18000000136400EE0200000000000000000000000040B000", "string": "-750" }, { "description": "[decq164] fold-downs (more below)", "subject": "1800000013640039300000000000000000000000003CB000", "string": "-123.45" }, { "description": "[decq156] fold-downs (more below)", "subject": "180000001364007B0000000000000000000000000040B000", "string": "-123" }, { "description": "[decq008] derivative canonical plain strings", "subject": "18000000136400EE020000000000000000000000003EB000", "string": "-75.0" }, { "description": "[decq158] fold-downs (more below)", "subject": "180000001364000C0000000000000000000000000040B000", "string": "-12" }, { "description": "[decq122] Nmax and similar", "subject": "18000000136400FFFFFFFF638E8D37C087ADBE09EDFFDF00", "string": "-9.999999999999999999999999999999999E+6144" }, { "description": "[decq002] (mostly derived from the Strawman 4 document and examples)", "subject": "18000000136400EE020000000000000000000000003CB000", "string": "-7.50" }, { "description": "[decq004] derivative canonical plain strings", "subject": "18000000136400EE0200000000000000000000000042B000", "string": "-7.50E+3" }, { "description": "[decq018] derivative canonical plain strings", "subject": "18000000136400EE020000000000000000000000002EB000", "string": "-7.50E-7" }, { "description": "[decq125] Nmax and similar", "subject": "18000000136400F2AF967ED05C82DE3297FF6FDE3CFEDF00", "string": "-1.234567890123456789012345678901234E+6144" }, { "description": "[decq131] fold-downs (more below)", "subject": "18000000136400000000807F1BCF85B27059C8A43CFEDF00", "string": "-1.230000000000000000000000000000000E+6144" }, { "description": "[decq162] fold-downs (more below)", "subject": "180000001364007B000000000000000000000000003CB000", "string": "-1.23" }, { "description": "[decq176] Nmin and below", "subject": "18000000136400010000000A5BC138938D44C64D31008000", "string": "-1.000000000000000000000000000000001E-6143" }, { "description": "[decq174] Nmin and below", "subject": "18000000136400000000000A5BC138938D44C64D31008000", "string": "-1.000000000000000000000000000000000E-6143" }, { "description": "[decq133] fold-downs (more below)", "subject": "18000000136400000000000A5BC138938D44C64D31FEDF00", "string": "-1.000000000000000000000000000000000E+6144" }, { "description": "[decq160] fold-downs (more below)", "subject": "18000000136400010000000000000000000000000040B000", "string": "-1" }, { "description": "[decq172] Nmin and below", "subject": "180000001364000100000000000000000000000000428000", "string": "-1E-6143" }, { "description": "[decq010] derivative canonical plain strings", "subject": "18000000136400EE020000000000000000000000003AB000", "string": "-0.750" }, { "description": "[decq012] derivative canonical plain strings", "subject": "18000000136400EE0200000000000000000000000038B000", "string": "-0.0750" }, { "description": "[decq014] derivative canonical plain strings", "subject": "18000000136400EE0200000000000000000000000034B000", "string": "-0.000750" }, { "description": "[decq016] derivative canonical plain strings", "subject": "18000000136400EE0200000000000000000000000030B000", "string": "-0.00000750" }, { "description": "[decq404] zeros", "subject": "180000001364000000000000000000000000000000000000", "string": "0E-6176" }, { "description": "[decq424] negative zeros", "subject": "180000001364000000000000000000000000000000008000", "string": "-0E-6176" }, { "description": "[decq407] zeros", "subject": "1800000013640000000000000000000000000000003C3000", "string": "0.00" }, { "description": "[decq427] negative zeros", "subject": "1800000013640000000000000000000000000000003CB000", "string": "-0.00" }, { "description": "[decq409] zeros", "subject": "180000001364000000000000000000000000000000403000", "string": "0" }, { "description": "[decq428] negative zeros", "subject": "18000000136400000000000000000000000000000040B000", "string": "-0" }, { "description": "[decq700] Selected DPD codes", "subject": "180000001364000000000000000000000000000000403000", "string": "0" }, { "description": "[decq406] zeros", "subject": "1800000013640000000000000000000000000000003C3000", "string": "0.00" }, { "description": "[decq426] negative zeros", "subject": "1800000013640000000000000000000000000000003CB000", "string": "-0.00" }, { "description": "[decq410] zeros", "subject": "180000001364000000000000000000000000000000463000", "string": "0E+3" }, { "description": "[decq431] negative zeros", "subject": "18000000136400000000000000000000000000000046B000", "string": "-0E+3" }, { "description": "[decq419] clamped zeros...", "subject": "180000001364000000000000000000000000000000FE5F00", "string": "0E+6111" }, { "description": "[decq432] negative zeros", "subject": "180000001364000000000000000000000000000000FEDF00", "string": "-0E+6111" }, { "description": "[decq405] zeros", "subject": "180000001364000000000000000000000000000000000000", "string": "0E-6176" }, { "description": "[decq425] negative zeros", "subject": "180000001364000000000000000000000000000000008000", "string": "-0E-6176" }, { "description": "[decq508] Specials", "subject": "180000001364000000000000000000000000000000007800", "string": "Infinity" }, { "description": "[decq528] Specials", "subject": "18000000136400000000000000000000000000000000F800", "string": "-Infinity" }, { "description": "[decq541] Specials", "subject": "180000001364000000000000000000000000000000007C00", "string": "NaN" }, { "description": "[decq074] Nmin and below", "subject": "18000000136400000000000A5BC138938D44C64D31000000", "string": "1.000000000000000000000000000000000E-6143" }, { "description": "[decq602] fold-down full sequence", "subject": "18000000136400000000000A5BC138938D44C64D31FE5F00", "string": "1.000000000000000000000000000000000E+6144" }, { "description": "[decq604] fold-down full sequence", "subject": "180000001364000000000081EFAC855B416D2DEE04FE5F00", "string": "1.00000000000000000000000000000000E+6143" }, { "description": "[decq606] fold-down full sequence", "subject": "1800000013640000000080264B91C02220BE377E00FE5F00", "string": "1.0000000000000000000000000000000E+6142" }, { "description": "[decq608] fold-down full sequence", "subject": "1800000013640000000040EAED7446D09C2C9F0C00FE5F00", "string": "1.000000000000000000000000000000E+6141" }, { "description": "[decq610] fold-down full sequence", "subject": "18000000136400000000A0CA17726DAE0F1E430100FE5F00", "string": "1.00000000000000000000000000000E+6140" }, { "description": "[decq612] fold-down full sequence", "subject": "18000000136400000000106102253E5ECE4F200000FE5F00", "string": "1.0000000000000000000000000000E+6139" }, { "description": "[decq614] fold-down full sequence", "subject": "18000000136400000000E83C80D09F3C2E3B030000FE5F00", "string": "1.000000000000000000000000000E+6138" }, { "description": "[decq616] fold-down full sequence", "subject": "18000000136400000000E4D20CC8DCD2B752000000FE5F00", "string": "1.00000000000000000000000000E+6137" }, { "description": "[decq618] fold-down full sequence", "subject": "180000001364000000004A48011416954508000000FE5F00", "string": "1.0000000000000000000000000E+6136" }, { "description": "[decq620] fold-down full sequence", "subject": "18000000136400000000A1EDCCCE1BC2D300000000FE5F00", "string": "1.000000000000000000000000E+6135" }, { "description": "[decq622] fold-down full sequence", "subject": "18000000136400000080F64AE1C7022D1500000000FE5F00", "string": "1.00000000000000000000000E+6134" }, { "description": "[decq624] fold-down full sequence", "subject": "18000000136400000040B2BAC9E0191E0200000000FE5F00", "string": "1.0000000000000000000000E+6133" }, { "description": "[decq626] fold-down full sequence", "subject": "180000001364000000A0DEC5ADC935360000000000FE5F00", "string": "1.000000000000000000000E+6132" }, { "description": "[decq628] fold-down full sequence", "subject": "18000000136400000010632D5EC76B050000000000FE5F00", "string": "1.00000000000000000000E+6131" }, { "description": "[decq630] fold-down full sequence", "subject": "180000001364000000E8890423C78A000000000000FE5F00", "string": "1.0000000000000000000E+6130" }, { "description": "[decq632] fold-down full sequence", "subject": "18000000136400000064A7B3B6E00D000000000000FE5F00", "string": "1.000000000000000000E+6129" }, { "description": "[decq634] fold-down full sequence", "subject": "1800000013640000008A5D78456301000000000000FE5F00", "string": "1.00000000000000000E+6128" }, { "description": "[decq636] fold-down full sequence", "subject": "180000001364000000C16FF2862300000000000000FE5F00", "string": "1.0000000000000000E+6127" }, { "description": "[decq638] fold-down full sequence", "subject": "180000001364000080C6A47E8D0300000000000000FE5F00", "string": "1.000000000000000E+6126" }, { "description": "[decq640] fold-down full sequence", "subject": "1800000013640000407A10F35A0000000000000000FE5F00", "string": "1.00000000000000E+6125" }, { "description": "[decq642] fold-down full sequence", "subject": "1800000013640000A0724E18090000000000000000FE5F00", "string": "1.0000000000000E+6124" }, { "description": "[decq644] fold-down full sequence", "subject": "180000001364000010A5D4E8000000000000000000FE5F00", "string": "1.000000000000E+6123" }, { "description": "[decq646] fold-down full sequence", "subject": "1800000013640000E8764817000000000000000000FE5F00", "string": "1.00000000000E+6122" }, { "description": "[decq648] fold-down full sequence", "subject": "1800000013640000E40B5402000000000000000000FE5F00", "string": "1.0000000000E+6121" }, { "description": "[decq650] fold-down full sequence", "subject": "1800000013640000CA9A3B00000000000000000000FE5F00", "string": "1.000000000E+6120" }, { "description": "[decq652] fold-down full sequence", "subject": "1800000013640000E1F50500000000000000000000FE5F00", "string": "1.00000000E+6119" }, { "description": "[decq654] fold-down full sequence", "subject": "180000001364008096980000000000000000000000FE5F00", "string": "1.0000000E+6118" }, { "description": "[decq656] fold-down full sequence", "subject": "1800000013640040420F0000000000000000000000FE5F00", "string": "1.000000E+6117" }, { "description": "[decq658] fold-down full sequence", "subject": "18000000136400A086010000000000000000000000FE5F00", "string": "1.00000E+6116" }, { "description": "[decq660] fold-down full sequence", "subject": "180000001364001027000000000000000000000000FE5F00", "string": "1.0000E+6115" }, { "description": "[decq662] fold-down full sequence", "subject": "18000000136400E803000000000000000000000000FE5F00", "string": "1.000E+6114" }, { "description": "[decq664] fold-down full sequence", "subject": "180000001364006400000000000000000000000000FE5F00", "string": "1.00E+6113" }, { "description": "[decq666] fold-down full sequence", "subject": "180000001364000A00000000000000000000000000FE5F00", "string": "1.0E+6112" }, { "description": "[decq060] fold-downs (more below)", "subject": "180000001364000100000000000000000000000000403000", "string": "1" }, { "description": "[decq670] fold-down full sequence", "subject": "180000001364000100000000000000000000000000FC5F00", "string": "1E+6110" }, { "description": "[decq668] fold-down full sequence", "subject": "180000001364000100000000000000000000000000FE5F00", "string": "1E+6111" }, { "description": "[decq072] Nmin and below", "subject": "180000001364000100000000000000000000000000420000", "string": "1E-6143" }, { "description": "[decq076] Nmin and below", "subject": "18000000136400010000000A5BC138938D44C64D31000000", "string": "1.000000000000000000000000000000001E-6143" }, { "description": "[decq036] fold-downs (more below)", "subject": "18000000136400000000807F1BCF85B27059C8A43CFE5F00", "string": "1.230000000000000000000000000000000E+6144" }, { "description": "[decq062] fold-downs (more below)", "subject": "180000001364007B000000000000000000000000003C3000", "string": "1.23" }, { "description": "[decq034] Nmax and similar", "subject": "18000000136400F2AF967ED05C82DE3297FF6FDE3CFE5F00", "string": "1.234567890123456789012345678901234E+6144" }, { "description": "[decq441] exponent lengths", "subject": "180000001364000700000000000000000000000000403000", "string": "7" }, { "description": "[decq449] exponent lengths", "subject": "1800000013640007000000000000000000000000001E5F00", "string": "7E+5999" }, { "description": "[decq447] exponent lengths", "subject": "1800000013640007000000000000000000000000000E3800", "string": "7E+999" }, { "description": "[decq445] exponent lengths", "subject": "180000001364000700000000000000000000000000063100", "string": "7E+99" }, { "description": "[decq443] exponent lengths", "subject": "180000001364000700000000000000000000000000523000", "string": "7E+9" }, { "description": "[decq842] VG testcase", "subject": "180000001364000000FED83F4E7C9FE4E269E38A5BCD1700", "string": "7.049000000000010795488000000000000E-3097" }, { "description": "[decq841] VG testcase", "subject": "180000001364000000203B9DB5056F000000000000002400", "string": "8.000000000000000000E-1550" }, { "description": "[decq840] VG testcase", "subject": "180000001364003C17258419D710C42F0000000000002400", "string": "8.81125000000001349436E-1548" }, { "description": "[decq701] Selected DPD codes", "subject": "180000001364000900000000000000000000000000403000", "string": "9" }, { "description": "[decq032] Nmax and similar", "subject": "18000000136400FFFFFFFF638E8D37C087ADBE09EDFF5F00", "string": "9.999999999999999999999999999999999E+6144" }, { "description": "[decq702] Selected DPD codes", "subject": "180000001364000A00000000000000000000000000403000", "string": "10" }, { "description": "[decq057] fold-downs (more below)", "subject": "180000001364000C00000000000000000000000000403000", "string": "12" }, { "description": "[decq703] Selected DPD codes", "subject": "180000001364001300000000000000000000000000403000", "string": "19" }, { "description": "[decq704] Selected DPD codes", "subject": "180000001364001400000000000000000000000000403000", "string": "20" }, { "description": "[decq705] Selected DPD codes", "subject": "180000001364001D00000000000000000000000000403000", "string": "29" }, { "description": "[decq706] Selected DPD codes", "subject": "180000001364001E00000000000000000000000000403000", "string": "30" }, { "description": "[decq707] Selected DPD codes", "subject": "180000001364002700000000000000000000000000403000", "string": "39" }, { "description": "[decq708] Selected DPD codes", "subject": "180000001364002800000000000000000000000000403000", "string": "40" }, { "description": "[decq709] Selected DPD codes", "subject": "180000001364003100000000000000000000000000403000", "string": "49" }, { "description": "[decq710] Selected DPD codes", "subject": "180000001364003200000000000000000000000000403000", "string": "50" }, { "description": "[decq711] Selected DPD codes", "subject": "180000001364003B00000000000000000000000000403000", "string": "59" }, { "description": "[decq712] Selected DPD codes", "subject": "180000001364003C00000000000000000000000000403000", "string": "60" }, { "description": "[decq713] Selected DPD codes", "subject": "180000001364004500000000000000000000000000403000", "string": "69" }, { "description": "[decq714] Selected DPD codes", "subject": "180000001364004600000000000000000000000000403000", "string": "70" }, { "description": "[decq715] Selected DPD codes", "subject": "180000001364004700000000000000000000000000403000", "string": "71" }, { "description": "[decq716] Selected DPD codes", "subject": "180000001364004800000000000000000000000000403000", "string": "72" }, { "description": "[decq717] Selected DPD codes", "subject": "180000001364004900000000000000000000000000403000", "string": "73" }, { "description": "[decq718] Selected DPD codes", "subject": "180000001364004A00000000000000000000000000403000", "string": "74" }, { "description": "[decq719] Selected DPD codes", "subject": "180000001364004B00000000000000000000000000403000", "string": "75" }, { "description": "[decq720] Selected DPD codes", "subject": "180000001364004C00000000000000000000000000403000", "string": "76" }, { "description": "[decq721] Selected DPD codes", "subject": "180000001364004D00000000000000000000000000403000", "string": "77" }, { "description": "[decq722] Selected DPD codes", "subject": "180000001364004E00000000000000000000000000403000", "string": "78" }, { "description": "[decq723] Selected DPD codes", "subject": "180000001364004F00000000000000000000000000403000", "string": "79" }, { "description": "[decq056] fold-downs (more below)", "subject": "180000001364007B00000000000000000000000000403000", "string": "123" }, { "description": "[decq064] fold-downs (more below)", "subject": "1800000013640039300000000000000000000000003C3000", "string": "123.45" }, { "description": "[decq732] Selected DPD codes", "subject": "180000001364000802000000000000000000000000403000", "string": "520" }, { "description": "[decq733] Selected DPD codes", "subject": "180000001364000902000000000000000000000000403000", "string": "521" }, { "description": "[decq740] DPD: one of each of the huffman groups", "subject": "180000001364000903000000000000000000000000403000", "string": "777" }, { "description": "[decq741] DPD: one of each of the huffman groups", "subject": "180000001364000A03000000000000000000000000403000", "string": "778" }, { "description": "[decq742] DPD: one of each of the huffman groups", "subject": "180000001364001303000000000000000000000000403000", "string": "787" }, { "description": "[decq746] DPD: one of each of the huffman groups", "subject": "180000001364001F03000000000000000000000000403000", "string": "799" }, { "description": "[decq743] DPD: one of each of the huffman groups", "subject": "180000001364006D03000000000000000000000000403000", "string": "877" }, { "description": "[decq753] DPD all-highs cases (includes the 24 redundant codes)", "subject": "180000001364007803000000000000000000000000403000", "string": "888" }, { "description": "[decq754] DPD all-highs cases (includes the 24 redundant codes)", "subject": "180000001364007903000000000000000000000000403000", "string": "889" }, { "description": "[decq760] DPD all-highs cases (includes the 24 redundant codes)", "subject": "180000001364008203000000000000000000000000403000", "string": "898" }, { "description": "[decq764] DPD all-highs cases (includes the 24 redundant codes)", "subject": "180000001364008303000000000000000000000000403000", "string": "899" }, { "description": "[decq745] DPD: one of each of the huffman groups", "subject": "18000000136400D303000000000000000000000000403000", "string": "979" }, { "description": "[decq770] DPD all-highs cases (includes the 24 redundant codes)", "subject": "18000000136400DC03000000000000000000000000403000", "string": "988" }, { "description": "[decq774] DPD all-highs cases (includes the 24 redundant codes)", "subject": "18000000136400DD03000000000000000000000000403000", "string": "989" }, { "description": "[decq730] Selected DPD codes", "subject": "18000000136400E203000000000000000000000000403000", "string": "994" }, { "description": "[decq731] Selected DPD codes", "subject": "18000000136400E303000000000000000000000000403000", "string": "995" }, { "description": "[decq744] DPD: one of each of the huffman groups", "subject": "18000000136400E503000000000000000000000000403000", "string": "997" }, { "description": "[decq780] DPD all-highs cases (includes the 24 redundant codes)", "subject": "18000000136400E603000000000000000000000000403000", "string": "998" }, { "description": "[decq787] DPD all-highs cases (includes the 24 redundant codes)", "subject": "18000000136400E703000000000000000000000000403000", "string": "999" }, { "description": "[decq053] fold-downs (more below)", "subject": "18000000136400D204000000000000000000000000403000", "string": "1234" }, { "description": "[decq052] fold-downs (more below)", "subject": "180000001364003930000000000000000000000000403000", "string": "12345" }, { "description": "[decq792] Miscellaneous (testers' queries, etc.)", "subject": "180000001364003075000000000000000000000000403000", "string": "30000" }, { "description": "[decq793] Miscellaneous (testers' queries, etc.)", "subject": "1800000013640090940D0000000000000000000000403000", "string": "890000" }, { "description": "[decq824] values around [u]int32 edges (zeros done earlier)", "subject": "18000000136400FEFFFF7F00000000000000000000403000", "string": "2147483646" }, { "description": "[decq825] values around [u]int32 edges (zeros done earlier)", "subject": "18000000136400FFFFFF7F00000000000000000000403000", "string": "2147483647" }, { "description": "[decq826] values around [u]int32 edges (zeros done earlier)", "subject": "180000001364000000008000000000000000000000403000", "string": "2147483648" }, { "description": "[decq827] values around [u]int32 edges (zeros done earlier)", "subject": "180000001364000100008000000000000000000000403000", "string": "2147483649" }, { "description": "[decq828] values around [u]int32 edges (zeros done earlier)", "subject": "18000000136400FEFFFFFF00000000000000000000403000", "string": "4294967294" }, { "description": "[decq829] values around [u]int32 edges (zeros done earlier)", "subject": "18000000136400FFFFFFFF00000000000000000000403000", "string": "4294967295" }, { "description": "[decq830] values around [u]int32 edges (zeros done earlier)", "subject": "180000001364000000000001000000000000000000403000", "string": "4294967296" }, { "description": "[decq831] values around [u]int32 edges (zeros done earlier)", "subject": "180000001364000100000001000000000000000000403000", "string": "4294967297" }, { "description": "[decq022] Normality", "subject": "18000000136400C7711CC7B548F377DC80A131C836403000", "string": "1111111111111111111111111111111111" }, { "description": "[decq020] Normality", "subject": "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000", "string": "1234567890123456789012345678901234" }, { "description": "[decq550] Specials", "subject": "18000000136400FFFFFFFF638E8D37C087ADBE09ED413000", "string": "9999999999999999999999999999999999" } ] } bson-ruby-4.15.0/spec/spec_tests/data/decimal128/decimal128-3.json000066400000000000000000001754161423026727100242770ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "valid": [ { "description": "[basx066] strings without E cannot generate E in result", "subject": "18000000136400185C0ACE0000000000000000000038B000", "string": "-00345678.5432", "match_string": "-345678.5432" }, { "description": "[basx065] strings without E cannot generate E in result", "subject": "18000000136400185C0ACE0000000000000000000038B000", "string": "-0345678.5432", "match_string": "-345678.5432" }, { "description": "[basx064] strings without E cannot generate E in result", "subject": "18000000136400185C0ACE0000000000000000000038B000", "string": "-345678.5432" }, { "description": "[basx041] strings without E cannot generate E in result", "subject": "180000001364004C0000000000000000000000000040B000", "string": "-76" }, { "description": "[basx027] conform to rules and exponent will be in permitted range).", "subject": "180000001364000F270000000000000000000000003AB000", "string": "-9.999" }, { "description": "[basx026] conform to rules and exponent will be in permitted range).", "subject": "180000001364009F230000000000000000000000003AB000", "string": "-9.119" }, { "description": "[basx025] conform to rules and exponent will be in permitted range).", "subject": "180000001364008F030000000000000000000000003CB000", "string": "-9.11" }, { "description": "[basx024] conform to rules and exponent will be in permitted range).", "subject": "180000001364005B000000000000000000000000003EB000", "string": "-9.1" }, { "description": "[dqbsr531] negatives (Rounded)", "subject": "1800000013640099761CC7B548F377DC80A131C836FEAF00", "string": "-1.1111111111111111111111111111123450", "match_string": "-1.111111111111111111111111111112345" }, { "description": "[basx022] conform to rules and exponent will be in permitted range).", "subject": "180000001364000A000000000000000000000000003EB000", "string": "-1.0" }, { "description": "[basx021] conform to rules and exponent will be in permitted range).", "subject": "18000000136400010000000000000000000000000040B000", "string": "-1" }, { "description": "[basx601] Zeros", "subject": "1800000013640000000000000000000000000000002E3000", "string": "0.000000000", "match_string": "0E-9" }, { "description": "[basx622] Zeros", "subject": "1800000013640000000000000000000000000000002EB000", "string": "-0.000000000", "match_string": "-0E-9" }, { "description": "[basx602] Zeros", "subject": "180000001364000000000000000000000000000000303000", "string": "0.00000000", "match_string": "0E-8" }, { "description": "[basx621] Zeros", "subject": "18000000136400000000000000000000000000000030B000", "string": "-0.00000000", "match_string": "-0E-8" }, { "description": "[basx603] Zeros", "subject": "180000001364000000000000000000000000000000323000", "string": "0.0000000", "match_string": "0E-7" }, { "description": "[basx620] Zeros", "subject": "18000000136400000000000000000000000000000032B000", "string": "-0.0000000", "match_string": "-0E-7" }, { "description": "[basx604] Zeros", "subject": "180000001364000000000000000000000000000000343000", "string": "0.000000" }, { "description": "[basx619] Zeros", "subject": "18000000136400000000000000000000000000000034B000", "string": "-0.000000" }, { "description": "[basx605] Zeros", "subject": "180000001364000000000000000000000000000000363000", "string": "0.00000" }, { "description": "[basx618] Zeros", "subject": "18000000136400000000000000000000000000000036B000", "string": "-0.00000" }, { "description": "[basx680] Zeros", "subject": "180000001364000000000000000000000000000000403000", "string": "000000.", "match_string": "0" }, { "description": "[basx606] Zeros", "subject": "180000001364000000000000000000000000000000383000", "string": "0.0000" }, { "description": "[basx617] Zeros", "subject": "18000000136400000000000000000000000000000038B000", "string": "-0.0000" }, { "description": "[basx681] Zeros", "subject": "180000001364000000000000000000000000000000403000", "string": "00000.", "match_string": "0" }, { "description": "[basx686] Zeros", "subject": "180000001364000000000000000000000000000000403000", "string": "+00000.", "match_string": "0" }, { "description": "[basx687] Zeros", "subject": "18000000136400000000000000000000000000000040B000", "string": "-00000.", "match_string": "-0" }, { "description": "[basx019] conform to rules and exponent will be in permitted range).", "subject": "1800000013640000000000000000000000000000003CB000", "string": "-00.00", "match_string": "-0.00" }, { "description": "[basx607] Zeros", "subject": "1800000013640000000000000000000000000000003A3000", "string": "0.000" }, { "description": "[basx616] Zeros", "subject": "1800000013640000000000000000000000000000003AB000", "string": "-0.000" }, { "description": "[basx682] Zeros", "subject": "180000001364000000000000000000000000000000403000", "string": "0000.", "match_string": "0" }, { "description": "[basx155] Numbers with E", "subject": "1800000013640000000000000000000000000000003A3000", "string": "0.000e+0", "match_string": "0.000" }, { "description": "[basx130] Numbers with E", "subject": "180000001364000000000000000000000000000000383000", "string": "0.000E-1", "match_string": "0.0000" }, { "description": "[basx290] some more negative zeros [systematic tests below]", "subject": "18000000136400000000000000000000000000000038B000", "string": "-0.000E-1", "match_string": "-0.0000" }, { "description": "[basx131] Numbers with E", "subject": "180000001364000000000000000000000000000000363000", "string": "0.000E-2", "match_string": "0.00000" }, { "description": "[basx291] some more negative zeros [systematic tests below]", "subject": "18000000136400000000000000000000000000000036B000", "string": "-0.000E-2", "match_string": "-0.00000" }, { "description": "[basx132] Numbers with E", "subject": "180000001364000000000000000000000000000000343000", "string": "0.000E-3", "match_string": "0.000000" }, { "description": "[basx292] some more negative zeros [systematic tests below]", "subject": "18000000136400000000000000000000000000000034B000", "string": "-0.000E-3", "match_string": "-0.000000" }, { "description": "[basx133] Numbers with E", "subject": "180000001364000000000000000000000000000000323000", "string": "0.000E-4", "match_string": "0E-7" }, { "description": "[basx293] some more negative zeros [systematic tests below]", "subject": "18000000136400000000000000000000000000000032B000", "string": "-0.000E-4", "match_string": "-0E-7" }, { "description": "[basx608] Zeros", "subject": "1800000013640000000000000000000000000000003C3000", "string": "0.00" }, { "description": "[basx615] Zeros", "subject": "1800000013640000000000000000000000000000003CB000", "string": "-0.00" }, { "description": "[basx683] Zeros", "subject": "180000001364000000000000000000000000000000403000", "string": "000.", "match_string": "0" }, { "description": "[basx630] Zeros", "subject": "1800000013640000000000000000000000000000003C3000", "string": "0.00E+0", "match_string": "0.00" }, { "description": "[basx670] Zeros", "subject": "1800000013640000000000000000000000000000003C3000", "string": "0.00E-0", "match_string": "0.00" }, { "description": "[basx631] Zeros", "subject": "1800000013640000000000000000000000000000003E3000", "string": "0.00E+1", "match_string": "0.0" }, { "description": "[basx671] Zeros", "subject": "1800000013640000000000000000000000000000003A3000", "string": "0.00E-1", "match_string": "0.000" }, { "description": "[basx134] Numbers with E", "subject": "180000001364000000000000000000000000000000383000", "string": "0.00E-2", "match_string": "0.0000" }, { "description": "[basx294] some more negative zeros [systematic tests below]", "subject": "18000000136400000000000000000000000000000038B000", "string": "-0.00E-2", "match_string": "-0.0000" }, { "description": "[basx632] Zeros", "subject": "180000001364000000000000000000000000000000403000", "string": "0.00E+2", "match_string": "0" }, { "description": "[basx672] Zeros", "subject": "180000001364000000000000000000000000000000383000", "string": "0.00E-2", "match_string": "0.0000" }, { "description": "[basx135] Numbers with E", "subject": "180000001364000000000000000000000000000000363000", "string": "0.00E-3", "match_string": "0.00000" }, { "description": "[basx295] some more negative zeros [systematic tests below]", "subject": "18000000136400000000000000000000000000000036B000", "string": "-0.00E-3", "match_string": "-0.00000" }, { "description": "[basx633] Zeros", "subject": "180000001364000000000000000000000000000000423000", "string": "0.00E+3", "match_string": "0E+1" }, { "description": "[basx673] Zeros", "subject": "180000001364000000000000000000000000000000363000", "string": "0.00E-3", "match_string": "0.00000" }, { "description": "[basx136] Numbers with E", "subject": "180000001364000000000000000000000000000000343000", "string": "0.00E-4", "match_string": "0.000000" }, { "description": "[basx674] Zeros", "subject": "180000001364000000000000000000000000000000343000", "string": "0.00E-4", "match_string": "0.000000" }, { "description": "[basx634] Zeros", "subject": "180000001364000000000000000000000000000000443000", "string": "0.00E+4", "match_string": "0E+2" }, { "description": "[basx137] Numbers with E", "subject": "180000001364000000000000000000000000000000323000", "string": "0.00E-5", "match_string": "0E-7" }, { "description": "[basx635] Zeros", "subject": "180000001364000000000000000000000000000000463000", "string": "0.00E+5", "match_string": "0E+3" }, { "description": "[basx675] Zeros", "subject": "180000001364000000000000000000000000000000323000", "string": "0.00E-5", "match_string": "0E-7" }, { "description": "[basx636] Zeros", "subject": "180000001364000000000000000000000000000000483000", "string": "0.00E+6", "match_string": "0E+4" }, { "description": "[basx676] Zeros", "subject": "180000001364000000000000000000000000000000303000", "string": "0.00E-6", "match_string": "0E-8" }, { "description": "[basx637] Zeros", "subject": "1800000013640000000000000000000000000000004A3000", "string": "0.00E+7", "match_string": "0E+5" }, { "description": "[basx677] Zeros", "subject": "1800000013640000000000000000000000000000002E3000", "string": "0.00E-7", "match_string": "0E-9" }, { "description": "[basx638] Zeros", "subject": "1800000013640000000000000000000000000000004C3000", "string": "0.00E+8", "match_string": "0E+6" }, { "description": "[basx678] Zeros", "subject": "1800000013640000000000000000000000000000002C3000", "string": "0.00E-8", "match_string": "0E-10" }, { "description": "[basx149] Numbers with E", "subject": "180000001364000000000000000000000000000000523000", "string": "000E+9", "match_string": "0E+9" }, { "description": "[basx639] Zeros", "subject": "1800000013640000000000000000000000000000004E3000", "string": "0.00E+9", "match_string": "0E+7" }, { "description": "[basx679] Zeros", "subject": "1800000013640000000000000000000000000000002A3000", "string": "0.00E-9", "match_string": "0E-11" }, { "description": "[basx063] strings without E cannot generate E in result", "subject": "18000000136400185C0ACE00000000000000000000383000", "string": "+00345678.5432", "match_string": "345678.5432" }, { "description": "[basx018] conform to rules and exponent will be in permitted range).", "subject": "1800000013640000000000000000000000000000003EB000", "string": "-0.0" }, { "description": "[basx609] Zeros", "subject": "1800000013640000000000000000000000000000003E3000", "string": "0.0" }, { "description": "[basx614] Zeros", "subject": "1800000013640000000000000000000000000000003EB000", "string": "-0.0" }, { "description": "[basx684] Zeros", "subject": "180000001364000000000000000000000000000000403000", "string": "00.", "match_string": "0" }, { "description": "[basx640] Zeros", "subject": "1800000013640000000000000000000000000000003E3000", "string": "0.0E+0", "match_string": "0.0" }, { "description": "[basx660] Zeros", "subject": "1800000013640000000000000000000000000000003E3000", "string": "0.0E-0", "match_string": "0.0" }, { "description": "[basx641] Zeros", "subject": "180000001364000000000000000000000000000000403000", "string": "0.0E+1", "match_string": "0" }, { "description": "[basx661] Zeros", "subject": "1800000013640000000000000000000000000000003C3000", "string": "0.0E-1", "match_string": "0.00" }, { "description": "[basx296] some more negative zeros [systematic tests below]", "subject": "1800000013640000000000000000000000000000003AB000", "string": "-0.0E-2", "match_string": "-0.000" }, { "description": "[basx642] Zeros", "subject": "180000001364000000000000000000000000000000423000", "string": "0.0E+2", "match_string": "0E+1" }, { "description": "[basx662] Zeros", "subject": "1800000013640000000000000000000000000000003A3000", "string": "0.0E-2", "match_string": "0.000" }, { "description": "[basx297] some more negative zeros [systematic tests below]", "subject": "18000000136400000000000000000000000000000038B000", "string": "-0.0E-3", "match_string": "-0.0000" }, { "description": "[basx643] Zeros", "subject": "180000001364000000000000000000000000000000443000", "string": "0.0E+3", "match_string": "0E+2" }, { "description": "[basx663] Zeros", "subject": "180000001364000000000000000000000000000000383000", "string": "0.0E-3", "match_string": "0.0000" }, { "description": "[basx644] Zeros", "subject": "180000001364000000000000000000000000000000463000", "string": "0.0E+4", "match_string": "0E+3" }, { "description": "[basx664] Zeros", "subject": "180000001364000000000000000000000000000000363000", "string": "0.0E-4", "match_string": "0.00000" }, { "description": "[basx645] Zeros", "subject": "180000001364000000000000000000000000000000483000", "string": "0.0E+5", "match_string": "0E+4" }, { "description": "[basx665] Zeros", "subject": "180000001364000000000000000000000000000000343000", "string": "0.0E-5", "match_string": "0.000000" }, { "description": "[basx646] Zeros", "subject": "1800000013640000000000000000000000000000004A3000", "string": "0.0E+6", "match_string": "0E+5" }, { "description": "[basx666] Zeros", "subject": "180000001364000000000000000000000000000000323000", "string": "0.0E-6", "match_string": "0E-7" }, { "description": "[basx647] Zeros", "subject": "1800000013640000000000000000000000000000004C3000", "string": "0.0E+7", "match_string": "0E+6" }, { "description": "[basx667] Zeros", "subject": "180000001364000000000000000000000000000000303000", "string": "0.0E-7", "match_string": "0E-8" }, { "description": "[basx648] Zeros", "subject": "1800000013640000000000000000000000000000004E3000", "string": "0.0E+8", "match_string": "0E+7" }, { "description": "[basx668] Zeros", "subject": "1800000013640000000000000000000000000000002E3000", "string": "0.0E-8", "match_string": "0E-9" }, { "description": "[basx160] Numbers with E", "subject": "180000001364000000000000000000000000000000523000", "string": "00E+9", "match_string": "0E+9" }, { "description": "[basx161] Numbers with E", "subject": "1800000013640000000000000000000000000000002E3000", "string": "00E-9", "match_string": "0E-9" }, { "description": "[basx649] Zeros", "subject": "180000001364000000000000000000000000000000503000", "string": "0.0E+9", "match_string": "0E+8" }, { "description": "[basx669] Zeros", "subject": "1800000013640000000000000000000000000000002C3000", "string": "0.0E-9", "match_string": "0E-10" }, { "description": "[basx062] strings without E cannot generate E in result", "subject": "18000000136400185C0ACE00000000000000000000383000", "string": "+0345678.5432", "match_string": "345678.5432" }, { "description": "[basx001] conform to rules and exponent will be in permitted range).", "subject": "180000001364000000000000000000000000000000403000", "string": "0" }, { "description": "[basx017] conform to rules and exponent will be in permitted range).", "subject": "18000000136400000000000000000000000000000040B000", "string": "-0" }, { "description": "[basx611] Zeros", "subject": "180000001364000000000000000000000000000000403000", "string": "0.", "match_string": "0" }, { "description": "[basx613] Zeros", "subject": "18000000136400000000000000000000000000000040B000", "string": "-0.", "match_string": "-0" }, { "description": "[basx685] Zeros", "subject": "180000001364000000000000000000000000000000403000", "string": "0.", "match_string": "0" }, { "description": "[basx688] Zeros", "subject": "180000001364000000000000000000000000000000403000", "string": "+0.", "match_string": "0" }, { "description": "[basx689] Zeros", "subject": "18000000136400000000000000000000000000000040B000", "string": "-0.", "match_string": "-0" }, { "description": "[basx650] Zeros", "subject": "180000001364000000000000000000000000000000403000", "string": "0E+0", "match_string": "0" }, { "description": "[basx651] Zeros", "subject": "180000001364000000000000000000000000000000423000", "string": "0E+1" }, { "description": "[basx298] some more negative zeros [systematic tests below]", "subject": "1800000013640000000000000000000000000000003CB000", "string": "-0E-2", "match_string": "-0.00" }, { "description": "[basx652] Zeros", "subject": "180000001364000000000000000000000000000000443000", "string": "0E+2" }, { "description": "[basx299] some more negative zeros [systematic tests below]", "subject": "1800000013640000000000000000000000000000003AB000", "string": "-0E-3", "match_string": "-0.000" }, { "description": "[basx653] Zeros", "subject": "180000001364000000000000000000000000000000463000", "string": "0E+3" }, { "description": "[basx654] Zeros", "subject": "180000001364000000000000000000000000000000483000", "string": "0E+4" }, { "description": "[basx655] Zeros", "subject": "1800000013640000000000000000000000000000004A3000", "string": "0E+5" }, { "description": "[basx656] Zeros", "subject": "1800000013640000000000000000000000000000004C3000", "string": "0E+6" }, { "description": "[basx657] Zeros", "subject": "1800000013640000000000000000000000000000004E3000", "string": "0E+7" }, { "description": "[basx658] Zeros", "subject": "180000001364000000000000000000000000000000503000", "string": "0E+8" }, { "description": "[basx138] Numbers with E", "subject": "180000001364000000000000000000000000000000523000", "string": "+0E+9", "match_string": "0E+9" }, { "description": "[basx139] Numbers with E", "subject": "18000000136400000000000000000000000000000052B000", "string": "-0E+9" }, { "description": "[basx144] Numbers with E", "subject": "180000001364000000000000000000000000000000523000", "string": "0E+9" }, { "description": "[basx154] Numbers with E", "subject": "180000001364000000000000000000000000000000523000", "string": "0E9", "match_string": "0E+9" }, { "description": "[basx659] Zeros", "subject": "180000001364000000000000000000000000000000523000", "string": "0E+9" }, { "description": "[basx042] strings without E cannot generate E in result", "subject": "18000000136400FC040000000000000000000000003C3000", "string": "+12.76", "match_string": "12.76" }, { "description": "[basx143] Numbers with E", "subject": "180000001364000100000000000000000000000000523000", "string": "+1E+009", "match_string": "1E+9" }, { "description": "[basx061] strings without E cannot generate E in result", "subject": "18000000136400185C0ACE00000000000000000000383000", "string": "+345678.5432", "match_string": "345678.5432" }, { "description": "[basx036] conform to rules and exponent will be in permitted range).", "subject": "1800000013640015CD5B0700000000000000000000203000", "string": "0.0000000123456789", "match_string": "1.23456789E-8" }, { "description": "[basx035] conform to rules and exponent will be in permitted range).", "subject": "1800000013640015CD5B0700000000000000000000223000", "string": "0.000000123456789", "match_string": "1.23456789E-7" }, { "description": "[basx034] conform to rules and exponent will be in permitted range).", "subject": "1800000013640015CD5B0700000000000000000000243000", "string": "0.00000123456789" }, { "description": "[basx053] strings without E cannot generate E in result", "subject": "180000001364003200000000000000000000000000323000", "string": "0.0000050" }, { "description": "[basx033] conform to rules and exponent will be in permitted range).", "subject": "1800000013640015CD5B0700000000000000000000263000", "string": "0.0000123456789" }, { "description": "[basx016] conform to rules and exponent will be in permitted range).", "subject": "180000001364000C000000000000000000000000003A3000", "string": "0.012" }, { "description": "[basx015] conform to rules and exponent will be in permitted range).", "subject": "180000001364007B000000000000000000000000003A3000", "string": "0.123" }, { "description": "[basx037] conform to rules and exponent will be in permitted range).", "subject": "1800000013640078DF0D8648700000000000000000223000", "string": "0.123456789012344" }, { "description": "[basx038] conform to rules and exponent will be in permitted range).", "subject": "1800000013640079DF0D8648700000000000000000223000", "string": "0.123456789012345" }, { "description": "[basx250] Numbers with E", "subject": "18000000136400F104000000000000000000000000383000", "string": "0.1265" }, { "description": "[basx257] Numbers with E", "subject": "18000000136400F104000000000000000000000000383000", "string": "0.1265E-0", "match_string": "0.1265" }, { "description": "[basx256] Numbers with E", "subject": "18000000136400F104000000000000000000000000363000", "string": "0.1265E-1", "match_string": "0.01265" }, { "description": "[basx258] Numbers with E", "subject": "18000000136400F1040000000000000000000000003A3000", "string": "0.1265E+1", "match_string": "1.265" }, { "description": "[basx251] Numbers with E", "subject": "18000000136400F104000000000000000000000000103000", "string": "0.1265E-20", "match_string": "1.265E-21" }, { "description": "[basx263] Numbers with E", "subject": "18000000136400F104000000000000000000000000603000", "string": "0.1265E+20", "match_string": "1.265E+19" }, { "description": "[basx255] Numbers with E", "subject": "18000000136400F104000000000000000000000000343000", "string": "0.1265E-2", "match_string": "0.001265" }, { "description": "[basx259] Numbers with E", "subject": "18000000136400F1040000000000000000000000003C3000", "string": "0.1265E+2", "match_string": "12.65" }, { "description": "[basx254] Numbers with E", "subject": "18000000136400F104000000000000000000000000323000", "string": "0.1265E-3", "match_string": "0.0001265" }, { "description": "[basx260] Numbers with E", "subject": "18000000136400F1040000000000000000000000003E3000", "string": "0.1265E+3", "match_string": "126.5" }, { "description": "[basx253] Numbers with E", "subject": "18000000136400F104000000000000000000000000303000", "string": "0.1265E-4", "match_string": "0.00001265" }, { "description": "[basx261] Numbers with E", "subject": "18000000136400F104000000000000000000000000403000", "string": "0.1265E+4", "match_string": "1265" }, { "description": "[basx252] Numbers with E", "subject": "18000000136400F104000000000000000000000000283000", "string": "0.1265E-8", "match_string": "1.265E-9" }, { "description": "[basx262] Numbers with E", "subject": "18000000136400F104000000000000000000000000483000", "string": "0.1265E+8", "match_string": "1.265E+7" }, { "description": "[basx159] Numbers with E", "subject": "1800000013640049000000000000000000000000002E3000", "string": "0.73e-7", "match_string": "7.3E-8" }, { "description": "[basx004] conform to rules and exponent will be in permitted range).", "subject": "1800000013640064000000000000000000000000003C3000", "string": "1.00" }, { "description": "[basx003] conform to rules and exponent will be in permitted range).", "subject": "180000001364000A000000000000000000000000003E3000", "string": "1.0" }, { "description": "[basx002] conform to rules and exponent will be in permitted range).", "subject": "180000001364000100000000000000000000000000403000", "string": "1" }, { "description": "[basx148] Numbers with E", "subject": "180000001364000100000000000000000000000000523000", "string": "1E+009", "match_string": "1E+9" }, { "description": "[basx153] Numbers with E", "subject": "180000001364000100000000000000000000000000523000", "string": "1E009", "match_string": "1E+9" }, { "description": "[basx141] Numbers with E", "subject": "180000001364000100000000000000000000000000523000", "string": "1e+09", "match_string": "1E+9" }, { "description": "[basx146] Numbers with E", "subject": "180000001364000100000000000000000000000000523000", "string": "1E+09", "match_string": "1E+9" }, { "description": "[basx151] Numbers with E", "subject": "180000001364000100000000000000000000000000523000", "string": "1e09", "match_string": "1E+9" }, { "description": "[basx142] Numbers with E", "subject": "180000001364000100000000000000000000000000F43000", "string": "1E+90" }, { "description": "[basx147] Numbers with E", "subject": "180000001364000100000000000000000000000000F43000", "string": "1e+90", "match_string": "1E+90" }, { "description": "[basx152] Numbers with E", "subject": "180000001364000100000000000000000000000000F43000", "string": "1E90", "match_string": "1E+90" }, { "description": "[basx140] Numbers with E", "subject": "180000001364000100000000000000000000000000523000", "string": "1E+9" }, { "description": "[basx150] Numbers with E", "subject": "180000001364000100000000000000000000000000523000", "string": "1E9", "match_string": "1E+9" }, { "description": "[basx014] conform to rules and exponent will be in permitted range).", "subject": "18000000136400D2040000000000000000000000003A3000", "string": "1.234" }, { "description": "[basx170] Numbers with E", "subject": "18000000136400F1040000000000000000000000003A3000", "string": "1.265" }, { "description": "[basx177] Numbers with E", "subject": "18000000136400F1040000000000000000000000003A3000", "string": "1.265E-0", "match_string": "1.265" }, { "description": "[basx176] Numbers with E", "subject": "18000000136400F104000000000000000000000000383000", "string": "1.265E-1", "match_string": "0.1265" }, { "description": "[basx178] Numbers with E", "subject": "18000000136400F1040000000000000000000000003C3000", "string": "1.265E+1", "match_string": "12.65" }, { "description": "[basx171] Numbers with E", "subject": "18000000136400F104000000000000000000000000123000", "string": "1.265E-20" }, { "description": "[basx183] Numbers with E", "subject": "18000000136400F104000000000000000000000000623000", "string": "1.265E+20" }, { "description": "[basx175] Numbers with E", "subject": "18000000136400F104000000000000000000000000363000", "string": "1.265E-2", "match_string": "0.01265" }, { "description": "[basx179] Numbers with E", "subject": "18000000136400F1040000000000000000000000003E3000", "string": "1.265E+2", "match_string": "126.5" }, { "description": "[basx174] Numbers with E", "subject": "18000000136400F104000000000000000000000000343000", "string": "1.265E-3", "match_string": "0.001265" }, { "description": "[basx180] Numbers with E", "subject": "18000000136400F104000000000000000000000000403000", "string": "1.265E+3", "match_string": "1265" }, { "description": "[basx173] Numbers with E", "subject": "18000000136400F104000000000000000000000000323000", "string": "1.265E-4", "match_string": "0.0001265" }, { "description": "[basx181] Numbers with E", "subject": "18000000136400F104000000000000000000000000423000", "string": "1.265E+4" }, { "description": "[basx172] Numbers with E", "subject": "18000000136400F1040000000000000000000000002A3000", "string": "1.265E-8" }, { "description": "[basx182] Numbers with E", "subject": "18000000136400F1040000000000000000000000004A3000", "string": "1.265E+8" }, { "description": "[basx157] Numbers with E", "subject": "180000001364000400000000000000000000000000523000", "string": "4E+9" }, { "description": "[basx067] examples", "subject": "180000001364000500000000000000000000000000343000", "string": "5E-6", "match_string": "0.000005" }, { "description": "[basx069] examples", "subject": "180000001364000500000000000000000000000000323000", "string": "5E-7" }, { "description": "[basx385] Engineering notation tests", "subject": "180000001364000700000000000000000000000000403000", "string": "7E0", "match_string": "7" }, { "description": "[basx365] Engineering notation tests", "subject": "180000001364000700000000000000000000000000543000", "string": "7E10", "match_string": "7E+10" }, { "description": "[basx405] Engineering notation tests", "subject": "1800000013640007000000000000000000000000002C3000", "string": "7E-10" }, { "description": "[basx363] Engineering notation tests", "subject": "180000001364000700000000000000000000000000563000", "string": "7E11", "match_string": "7E+11" }, { "description": "[basx407] Engineering notation tests", "subject": "1800000013640007000000000000000000000000002A3000", "string": "7E-11" }, { "description": "[basx361] Engineering notation tests", "subject": "180000001364000700000000000000000000000000583000", "string": "7E12", "match_string": "7E+12" }, { "description": "[basx409] Engineering notation tests", "subject": "180000001364000700000000000000000000000000283000", "string": "7E-12" }, { "description": "[basx411] Engineering notation tests", "subject": "180000001364000700000000000000000000000000263000", "string": "7E-13" }, { "description": "[basx383] Engineering notation tests", "subject": "180000001364000700000000000000000000000000423000", "string": "7E1", "match_string": "7E+1" }, { "description": "[basx387] Engineering notation tests", "subject": "1800000013640007000000000000000000000000003E3000", "string": "7E-1", "match_string": "0.7" }, { "description": "[basx381] Engineering notation tests", "subject": "180000001364000700000000000000000000000000443000", "string": "7E2", "match_string": "7E+2" }, { "description": "[basx389] Engineering notation tests", "subject": "1800000013640007000000000000000000000000003C3000", "string": "7E-2", "match_string": "0.07" }, { "description": "[basx379] Engineering notation tests", "subject": "180000001364000700000000000000000000000000463000", "string": "7E3", "match_string": "7E+3" }, { "description": "[basx391] Engineering notation tests", "subject": "1800000013640007000000000000000000000000003A3000", "string": "7E-3", "match_string": "0.007" }, { "description": "[basx377] Engineering notation tests", "subject": "180000001364000700000000000000000000000000483000", "string": "7E4", "match_string": "7E+4" }, { "description": "[basx393] Engineering notation tests", "subject": "180000001364000700000000000000000000000000383000", "string": "7E-4", "match_string": "0.0007" }, { "description": "[basx375] Engineering notation tests", "subject": "1800000013640007000000000000000000000000004A3000", "string": "7E5", "match_string": "7E+5" }, { "description": "[basx395] Engineering notation tests", "subject": "180000001364000700000000000000000000000000363000", "string": "7E-5", "match_string": "0.00007" }, { "description": "[basx373] Engineering notation tests", "subject": "1800000013640007000000000000000000000000004C3000", "string": "7E6", "match_string": "7E+6" }, { "description": "[basx397] Engineering notation tests", "subject": "180000001364000700000000000000000000000000343000", "string": "7E-6", "match_string": "0.000007" }, { "description": "[basx371] Engineering notation tests", "subject": "1800000013640007000000000000000000000000004E3000", "string": "7E7", "match_string": "7E+7" }, { "description": "[basx399] Engineering notation tests", "subject": "180000001364000700000000000000000000000000323000", "string": "7E-7" }, { "description": "[basx369] Engineering notation tests", "subject": "180000001364000700000000000000000000000000503000", "string": "7E8", "match_string": "7E+8" }, { "description": "[basx401] Engineering notation tests", "subject": "180000001364000700000000000000000000000000303000", "string": "7E-8" }, { "description": "[basx367] Engineering notation tests", "subject": "180000001364000700000000000000000000000000523000", "string": "7E9", "match_string": "7E+9" }, { "description": "[basx403] Engineering notation tests", "subject": "1800000013640007000000000000000000000000002E3000", "string": "7E-9" }, { "description": "[basx007] conform to rules and exponent will be in permitted range).", "subject": "1800000013640064000000000000000000000000003E3000", "string": "10.0" }, { "description": "[basx005] conform to rules and exponent will be in permitted range).", "subject": "180000001364000A00000000000000000000000000403000", "string": "10" }, { "description": "[basx165] Numbers with E", "subject": "180000001364000A00000000000000000000000000523000", "string": "10E+009", "match_string": "1.0E+10" }, { "description": "[basx163] Numbers with E", "subject": "180000001364000A00000000000000000000000000523000", "string": "10E+09", "match_string": "1.0E+10" }, { "description": "[basx325] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000403000", "string": "10e0", "match_string": "10" }, { "description": "[basx305] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000543000", "string": "10e10", "match_string": "1.0E+11" }, { "description": "[basx345] Engineering notation tests", "subject": "180000001364000A000000000000000000000000002C3000", "string": "10e-10", "match_string": "1.0E-9" }, { "description": "[basx303] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000563000", "string": "10e11", "match_string": "1.0E+12" }, { "description": "[basx347] Engineering notation tests", "subject": "180000001364000A000000000000000000000000002A3000", "string": "10e-11", "match_string": "1.0E-10" }, { "description": "[basx301] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000583000", "string": "10e12", "match_string": "1.0E+13" }, { "description": "[basx349] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000283000", "string": "10e-12", "match_string": "1.0E-11" }, { "description": "[basx351] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000263000", "string": "10e-13", "match_string": "1.0E-12" }, { "description": "[basx323] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000423000", "string": "10e1", "match_string": "1.0E+2" }, { "description": "[basx327] Engineering notation tests", "subject": "180000001364000A000000000000000000000000003E3000", "string": "10e-1", "match_string": "1.0" }, { "description": "[basx321] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000443000", "string": "10e2", "match_string": "1.0E+3" }, { "description": "[basx329] Engineering notation tests", "subject": "180000001364000A000000000000000000000000003C3000", "string": "10e-2", "match_string": "0.10" }, { "description": "[basx319] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000463000", "string": "10e3", "match_string": "1.0E+4" }, { "description": "[basx331] Engineering notation tests", "subject": "180000001364000A000000000000000000000000003A3000", "string": "10e-3", "match_string": "0.010" }, { "description": "[basx317] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000483000", "string": "10e4", "match_string": "1.0E+5" }, { "description": "[basx333] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000383000", "string": "10e-4", "match_string": "0.0010" }, { "description": "[basx315] Engineering notation tests", "subject": "180000001364000A000000000000000000000000004A3000", "string": "10e5", "match_string": "1.0E+6" }, { "description": "[basx335] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000363000", "string": "10e-5", "match_string": "0.00010" }, { "description": "[basx313] Engineering notation tests", "subject": "180000001364000A000000000000000000000000004C3000", "string": "10e6", "match_string": "1.0E+7" }, { "description": "[basx337] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000343000", "string": "10e-6", "match_string": "0.000010" }, { "description": "[basx311] Engineering notation tests", "subject": "180000001364000A000000000000000000000000004E3000", "string": "10e7", "match_string": "1.0E+8" }, { "description": "[basx339] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000323000", "string": "10e-7", "match_string": "0.0000010" }, { "description": "[basx309] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000503000", "string": "10e8", "match_string": "1.0E+9" }, { "description": "[basx341] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000303000", "string": "10e-8", "match_string": "1.0E-7" }, { "description": "[basx164] Numbers with E", "subject": "180000001364000A00000000000000000000000000F43000", "string": "10e+90", "match_string": "1.0E+91" }, { "description": "[basx162] Numbers with E", "subject": "180000001364000A00000000000000000000000000523000", "string": "10E+9", "match_string": "1.0E+10" }, { "description": "[basx307] Engineering notation tests", "subject": "180000001364000A00000000000000000000000000523000", "string": "10e9", "match_string": "1.0E+10" }, { "description": "[basx343] Engineering notation tests", "subject": "180000001364000A000000000000000000000000002E3000", "string": "10e-9", "match_string": "1.0E-8" }, { "description": "[basx008] conform to rules and exponent will be in permitted range).", "subject": "1800000013640065000000000000000000000000003E3000", "string": "10.1" }, { "description": "[basx009] conform to rules and exponent will be in permitted range).", "subject": "1800000013640068000000000000000000000000003E3000", "string": "10.4" }, { "description": "[basx010] conform to rules and exponent will be in permitted range).", "subject": "1800000013640069000000000000000000000000003E3000", "string": "10.5" }, { "description": "[basx011] conform to rules and exponent will be in permitted range).", "subject": "180000001364006A000000000000000000000000003E3000", "string": "10.6" }, { "description": "[basx012] conform to rules and exponent will be in permitted range).", "subject": "180000001364006D000000000000000000000000003E3000", "string": "10.9" }, { "description": "[basx013] conform to rules and exponent will be in permitted range).", "subject": "180000001364006E000000000000000000000000003E3000", "string": "11.0" }, { "description": "[basx040] strings without E cannot generate E in result", "subject": "180000001364000C00000000000000000000000000403000", "string": "12" }, { "description": "[basx190] Numbers with E", "subject": "18000000136400F1040000000000000000000000003C3000", "string": "12.65" }, { "description": "[basx197] Numbers with E", "subject": "18000000136400F1040000000000000000000000003C3000", "string": "12.65E-0", "match_string": "12.65" }, { "description": "[basx196] Numbers with E", "subject": "18000000136400F1040000000000000000000000003A3000", "string": "12.65E-1", "match_string": "1.265" }, { "description": "[basx198] Numbers with E", "subject": "18000000136400F1040000000000000000000000003E3000", "string": "12.65E+1", "match_string": "126.5" }, { "description": "[basx191] Numbers with E", "subject": "18000000136400F104000000000000000000000000143000", "string": "12.65E-20", "match_string": "1.265E-19" }, { "description": "[basx203] Numbers with E", "subject": "18000000136400F104000000000000000000000000643000", "string": "12.65E+20", "match_string": "1.265E+21" }, { "description": "[basx195] Numbers with E", "subject": "18000000136400F104000000000000000000000000383000", "string": "12.65E-2", "match_string": "0.1265" }, { "description": "[basx199] Numbers with E", "subject": "18000000136400F104000000000000000000000000403000", "string": "12.65E+2", "match_string": "1265" }, { "description": "[basx194] Numbers with E", "subject": "18000000136400F104000000000000000000000000363000", "string": "12.65E-3", "match_string": "0.01265" }, { "description": "[basx200] Numbers with E", "subject": "18000000136400F104000000000000000000000000423000", "string": "12.65E+3", "match_string": "1.265E+4" }, { "description": "[basx193] Numbers with E", "subject": "18000000136400F104000000000000000000000000343000", "string": "12.65E-4", "match_string": "0.001265" }, { "description": "[basx201] Numbers with E", "subject": "18000000136400F104000000000000000000000000443000", "string": "12.65E+4", "match_string": "1.265E+5" }, { "description": "[basx192] Numbers with E", "subject": "18000000136400F1040000000000000000000000002C3000", "string": "12.65E-8", "match_string": "1.265E-7" }, { "description": "[basx202] Numbers with E", "subject": "18000000136400F1040000000000000000000000004C3000", "string": "12.65E+8", "match_string": "1.265E+9" }, { "description": "[basx044] strings without E cannot generate E in result", "subject": "18000000136400FC040000000000000000000000003C3000", "string": "012.76", "match_string": "12.76" }, { "description": "[basx042] strings without E cannot generate E in result", "subject": "18000000136400FC040000000000000000000000003C3000", "string": "12.76" }, { "description": "[basx046] strings without E cannot generate E in result", "subject": "180000001364001100000000000000000000000000403000", "string": "17.", "match_string": "17" }, { "description": "[basx049] strings without E cannot generate E in result", "subject": "180000001364002C00000000000000000000000000403000", "string": "0044", "match_string": "44" }, { "description": "[basx048] strings without E cannot generate E in result", "subject": "180000001364002C00000000000000000000000000403000", "string": "044", "match_string": "44" }, { "description": "[basx158] Numbers with E", "subject": "180000001364002C00000000000000000000000000523000", "string": "44E+9", "match_string": "4.4E+10" }, { "description": "[basx068] examples", "subject": "180000001364003200000000000000000000000000323000", "string": "50E-7", "match_string": "0.0000050" }, { "description": "[basx169] Numbers with E", "subject": "180000001364006400000000000000000000000000523000", "string": "100e+009", "match_string": "1.00E+11" }, { "description": "[basx167] Numbers with E", "subject": "180000001364006400000000000000000000000000523000", "string": "100e+09", "match_string": "1.00E+11" }, { "description": "[basx168] Numbers with E", "subject": "180000001364006400000000000000000000000000F43000", "string": "100E+90", "match_string": "1.00E+92" }, { "description": "[basx166] Numbers with E", "subject": "180000001364006400000000000000000000000000523000", "string": "100e+9", "match_string": "1.00E+11" }, { "description": "[basx210] Numbers with E", "subject": "18000000136400F1040000000000000000000000003E3000", "string": "126.5" }, { "description": "[basx217] Numbers with E", "subject": "18000000136400F1040000000000000000000000003E3000", "string": "126.5E-0", "match_string": "126.5" }, { "description": "[basx216] Numbers with E", "subject": "18000000136400F1040000000000000000000000003C3000", "string": "126.5E-1", "match_string": "12.65" }, { "description": "[basx218] Numbers with E", "subject": "18000000136400F104000000000000000000000000403000", "string": "126.5E+1", "match_string": "1265" }, { "description": "[basx211] Numbers with E", "subject": "18000000136400F104000000000000000000000000163000", "string": "126.5E-20", "match_string": "1.265E-18" }, { "description": "[basx223] Numbers with E", "subject": "18000000136400F104000000000000000000000000663000", "string": "126.5E+20", "match_string": "1.265E+22" }, { "description": "[basx215] Numbers with E", "subject": "18000000136400F1040000000000000000000000003A3000", "string": "126.5E-2", "match_string": "1.265" }, { "description": "[basx219] Numbers with E", "subject": "18000000136400F104000000000000000000000000423000", "string": "126.5E+2", "match_string": "1.265E+4" }, { "description": "[basx214] Numbers with E", "subject": "18000000136400F104000000000000000000000000383000", "string": "126.5E-3", "match_string": "0.1265" }, { "description": "[basx220] Numbers with E", "subject": "18000000136400F104000000000000000000000000443000", "string": "126.5E+3", "match_string": "1.265E+5" }, { "description": "[basx213] Numbers with E", "subject": "18000000136400F104000000000000000000000000363000", "string": "126.5E-4", "match_string": "0.01265" }, { "description": "[basx221] Numbers with E", "subject": "18000000136400F104000000000000000000000000463000", "string": "126.5E+4", "match_string": "1.265E+6" }, { "description": "[basx212] Numbers with E", "subject": "18000000136400F1040000000000000000000000002E3000", "string": "126.5E-8", "match_string": "0.000001265" }, { "description": "[basx222] Numbers with E", "subject": "18000000136400F1040000000000000000000000004E3000", "string": "126.5E+8", "match_string": "1.265E+10" }, { "description": "[basx006] conform to rules and exponent will be in permitted range).", "subject": "18000000136400E803000000000000000000000000403000", "string": "1000" }, { "description": "[basx230] Numbers with E", "subject": "18000000136400F104000000000000000000000000403000", "string": "1265" }, { "description": "[basx237] Numbers with E", "subject": "18000000136400F104000000000000000000000000403000", "string": "1265E-0", "match_string": "1265" }, { "description": "[basx236] Numbers with E", "subject": "18000000136400F1040000000000000000000000003E3000", "string": "1265E-1", "match_string": "126.5" }, { "description": "[basx238] Numbers with E", "subject": "18000000136400F104000000000000000000000000423000", "string": "1265E+1", "match_string": "1.265E+4" }, { "description": "[basx231] Numbers with E", "subject": "18000000136400F104000000000000000000000000183000", "string": "1265E-20", "match_string": "1.265E-17" }, { "description": "[basx243] Numbers with E", "subject": "18000000136400F104000000000000000000000000683000", "string": "1265E+20", "match_string": "1.265E+23" }, { "description": "[basx235] Numbers with E", "subject": "18000000136400F1040000000000000000000000003C3000", "string": "1265E-2", "match_string": "12.65" }, { "description": "[basx239] Numbers with E", "subject": "18000000136400F104000000000000000000000000443000", "string": "1265E+2", "match_string": "1.265E+5" }, { "description": "[basx234] Numbers with E", "subject": "18000000136400F1040000000000000000000000003A3000", "string": "1265E-3", "match_string": "1.265" }, { "description": "[basx240] Numbers with E", "subject": "18000000136400F104000000000000000000000000463000", "string": "1265E+3", "match_string": "1.265E+6" }, { "description": "[basx233] Numbers with E", "subject": "18000000136400F104000000000000000000000000383000", "string": "1265E-4", "match_string": "0.1265" }, { "description": "[basx241] Numbers with E", "subject": "18000000136400F104000000000000000000000000483000", "string": "1265E+4", "match_string": "1.265E+7" }, { "description": "[basx232] Numbers with E", "subject": "18000000136400F104000000000000000000000000303000", "string": "1265E-8", "match_string": "0.00001265" }, { "description": "[basx242] Numbers with E", "subject": "18000000136400F104000000000000000000000000503000", "string": "1265E+8", "match_string": "1.265E+11" }, { "description": "[basx060] strings without E cannot generate E in result", "subject": "18000000136400185C0ACE00000000000000000000383000", "string": "345678.5432" }, { "description": "[basx059] strings without E cannot generate E in result", "subject": "18000000136400F198670C08000000000000000000363000", "string": "0345678.54321", "match_string": "345678.54321" }, { "description": "[basx058] strings without E cannot generate E in result", "subject": "180000001364006AF90B7C50000000000000000000343000", "string": "345678.543210" }, { "description": "[basx057] strings without E cannot generate E in result", "subject": "180000001364006A19562522020000000000000000343000", "string": "2345678.543210" }, { "description": "[basx056] strings without E cannot generate E in result", "subject": "180000001364006AB9C8733A0B0000000000000000343000", "string": "12345678.543210" }, { "description": "[basx031] conform to rules and exponent will be in permitted range).", "subject": "1800000013640040AF0D8648700000000000000000343000", "string": "123456789.000000" }, { "description": "[basx030] conform to rules and exponent will be in permitted range).", "subject": "1800000013640080910F8648700000000000000000343000", "string": "123456789.123456" }, { "description": "[basx032] conform to rules and exponent will be in permitted range).", "subject": "1800000013640080910F8648700000000000000000403000", "string": "123456789123456" } ] } bson-ruby-4.15.0/spec/spec_tests/data/decimal128/decimal128-4.json000066400000000000000000000135721423026727100242720ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "valid": [ { "description": "[basx023] conform to rules and exponent will be in permitted range).", "subject": "1800000013640001000000000000000000000000003EB000", "string": "-0.1" }, { "description": "[basx045] strings without E cannot generate E in result", "subject": "1800000013640003000000000000000000000000003A3000", "string": "+0.003", "match_string": "0.003" }, { "description": "[basx610] Zeros", "subject": "1800000013640000000000000000000000000000003E3000", "string": ".0", "match_string": "0.0" }, { "description": "[basx612] Zeros", "subject": "1800000013640000000000000000000000000000003EB000", "string": "-.0", "match_string": "-0.0" }, { "description": "[basx043] strings without E cannot generate E in result", "subject": "18000000136400FC040000000000000000000000003C3000", "string": "+12.76", "match_string": "12.76" }, { "description": "[basx055] strings without E cannot generate E in result", "subject": "180000001364000500000000000000000000000000303000", "string": "0.00000005", "match_string": "5E-8" }, { "description": "[basx054] strings without E cannot generate E in result", "subject": "180000001364000500000000000000000000000000323000", "string": "0.0000005", "match_string": "5E-7" }, { "description": "[basx052] strings without E cannot generate E in result", "subject": "180000001364000500000000000000000000000000343000", "string": "0.000005" }, { "description": "[basx051] strings without E cannot generate E in result", "subject": "180000001364000500000000000000000000000000363000", "string": "00.00005", "match_string": "0.00005" }, { "description": "[basx050] strings without E cannot generate E in result", "subject": "180000001364000500000000000000000000000000383000", "string": "0.0005" }, { "description": "[basx047] strings without E cannot generate E in result", "subject": "1800000013640005000000000000000000000000003E3000", "string": ".5", "match_string": "0.5" }, { "description": "[dqbsr431] check rounding modes heeded (Rounded)", "subject": "1800000013640099761CC7B548F377DC80A131C836FE2F00", "string": "1.1111111111111111111111111111123450", "match_string": "1.111111111111111111111111111112345" }, { "description": "OK2", "subject": "18000000136400000000000A5BC138938D44C64D31FC2F00", "string": ".100000000000000000000000000000000000000000000000000000000000", "match_string": "0.1000000000000000000000000000000000" } ], "parseErrors": [ { "description": "[basx564] Near-specials (Conversion_syntax)", "subject": "Infi" }, { "description": "[basx565] Near-specials (Conversion_syntax)", "subject": "Infin" }, { "description": "[basx566] Near-specials (Conversion_syntax)", "subject": "Infini" }, { "description": "[basx567] Near-specials (Conversion_syntax)", "subject": "Infinit" }, { "description": "[basx568] Near-specials (Conversion_syntax)", "subject": "-Infinit" }, { "description": "[basx590] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": ".Infinity" }, { "description": "[basx562] Near-specials (Conversion_syntax)", "subject": "NaNq" }, { "description": "[basx563] Near-specials (Conversion_syntax)", "subject": "NaNs" }, { "description": "[dqbas939] overflow results at different rounding modes (Overflow & Inexact & Rounded)", "subject": "-7e10000" }, { "description": "[dqbsr534] negatives (Rounded & Inexact)", "subject": "-1.11111111111111111111111111111234650" }, { "description": "[dqbsr535] negatives (Rounded & Inexact)", "subject": "-1.11111111111111111111111111111234551" }, { "description": "[dqbsr533] negatives (Rounded & Inexact)", "subject": "-1.11111111111111111111111111111234550" }, { "description": "[dqbsr532] negatives (Rounded & Inexact)", "subject": "-1.11111111111111111111111111111234549" }, { "description": "[dqbsr432] check rounding modes heeded (Rounded & Inexact)", "subject": "1.11111111111111111111111111111234549" }, { "description": "[dqbsr433] check rounding modes heeded (Rounded & Inexact)", "subject": "1.11111111111111111111111111111234550" }, { "description": "[dqbsr435] check rounding modes heeded (Rounded & Inexact)", "subject": "1.11111111111111111111111111111234551" }, { "description": "[dqbsr434] check rounding modes heeded (Rounded & Inexact)", "subject": "1.11111111111111111111111111111234650" }, { "description": "[dqbas938] overflow results at different rounding modes (Overflow & Inexact & Rounded)", "subject": "7e10000" }, { "description": "Inexact rounding#1", "subject": "100000000000000000000000000000000000000000000000000000000001" }, { "description": "Inexact rounding#2", "subject": "1E-6177" } ] } bson-ruby-4.15.0/spec/spec_tests/data/decimal128/decimal128-5.json000066400000000000000000000413371423026727100242730ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "valid": [ { "description": "[decq035] fold-downs (more below) (Clamped)", "subject": "18000000136400000000807F1BCF85B27059C8A43CFE5F00", "string": "1.23E+6144", "match_string": "1.230000000000000000000000000000000E+6144" }, { "description": "[decq037] fold-downs (more below) (Clamped)", "subject": "18000000136400000000000A5BC138938D44C64D31FE5F00", "string": "1E+6144", "match_string": "1.000000000000000000000000000000000E+6144" }, { "description": "[decq077] Nmin and below (Subnormal)", "subject": "180000001364000000000081EFAC855B416D2DEE04000000", "string": "0.100000000000000000000000000000000E-6143", "match_string": "1.00000000000000000000000000000000E-6144" }, { "description": "[decq078] Nmin and below (Subnormal)", "subject": "180000001364000000000081EFAC855B416D2DEE04000000", "string": "1.00000000000000000000000000000000E-6144" }, { "description": "[decq079] Nmin and below (Subnormal)", "subject": "180000001364000A00000000000000000000000000000000", "string": "0.000000000000000000000000000000010E-6143", "match_string": "1.0E-6175" }, { "description": "[decq080] Nmin and below (Subnormal)", "subject": "180000001364000A00000000000000000000000000000000", "string": "1.0E-6175" }, { "description": "[decq081] Nmin and below (Subnormal)", "subject": "180000001364000100000000000000000000000000020000", "string": "0.00000000000000000000000000000001E-6143", "match_string": "1E-6175" }, { "description": "[decq082] Nmin and below (Subnormal)", "subject": "180000001364000100000000000000000000000000020000", "string": "1E-6175" }, { "description": "[decq083] Nmin and below (Subnormal)", "subject": "180000001364000100000000000000000000000000000000", "string": "0.000000000000000000000000000000001E-6143", "match_string": "1E-6176" }, { "description": "[decq084] Nmin and below (Subnormal)", "subject": "180000001364000100000000000000000000000000000000", "string": "1E-6176" }, { "description": "[decq090] underflows cannot be tested for simple copies, check edge cases (Subnormal)", "subject": "180000001364000100000000000000000000000000000000", "string": "1e-6176", "match_string": "1E-6176" }, { "description": "[decq100] underflows cannot be tested for simple copies, check edge cases (Subnormal)", "subject": "18000000136400FFFFFFFF095BC138938D44C64D31000000", "string": "999999999999999999999999999999999e-6176", "match_string": "9.99999999999999999999999999999999E-6144" }, { "description": "[decq130] fold-downs (more below) (Clamped)", "subject": "18000000136400000000807F1BCF85B27059C8A43CFEDF00", "string": "-1.23E+6144", "match_string": "-1.230000000000000000000000000000000E+6144" }, { "description": "[decq132] fold-downs (more below) (Clamped)", "subject": "18000000136400000000000A5BC138938D44C64D31FEDF00", "string": "-1E+6144", "match_string": "-1.000000000000000000000000000000000E+6144" }, { "description": "[decq177] Nmin and below (Subnormal)", "subject": "180000001364000000000081EFAC855B416D2DEE04008000", "string": "-0.100000000000000000000000000000000E-6143", "match_string": "-1.00000000000000000000000000000000E-6144" }, { "description": "[decq178] Nmin and below (Subnormal)", "subject": "180000001364000000000081EFAC855B416D2DEE04008000", "string": "-1.00000000000000000000000000000000E-6144" }, { "description": "[decq179] Nmin and below (Subnormal)", "subject": "180000001364000A00000000000000000000000000008000", "string": "-0.000000000000000000000000000000010E-6143", "match_string": "-1.0E-6175" }, { "description": "[decq180] Nmin and below (Subnormal)", "subject": "180000001364000A00000000000000000000000000008000", "string": "-1.0E-6175" }, { "description": "[decq181] Nmin and below (Subnormal)", "subject": "180000001364000100000000000000000000000000028000", "string": "-0.00000000000000000000000000000001E-6143", "match_string": "-1E-6175" }, { "description": "[decq182] Nmin and below (Subnormal)", "subject": "180000001364000100000000000000000000000000028000", "string": "-1E-6175" }, { "description": "[decq183] Nmin and below (Subnormal)", "subject": "180000001364000100000000000000000000000000008000", "string": "-0.000000000000000000000000000000001E-6143", "match_string": "-1E-6176" }, { "description": "[decq184] Nmin and below (Subnormal)", "subject": "180000001364000100000000000000000000000000008000", "string": "-1E-6176" }, { "description": "[decq190] underflow edge cases (Subnormal)", "subject": "180000001364000100000000000000000000000000008000", "string": "-1e-6176", "match_string": "-1E-6176" }, { "description": "[decq200] underflow edge cases (Subnormal)", "subject": "18000000136400FFFFFFFF095BC138938D44C64D31008000", "string": "-999999999999999999999999999999999e-6176", "match_string": "-9.99999999999999999999999999999999E-6144" }, { "description": "[decq400] zeros (Clamped)", "subject": "180000001364000000000000000000000000000000000000", "string": "0E-8000", "match_string": "0E-6176" }, { "description": "[decq401] zeros (Clamped)", "subject": "180000001364000000000000000000000000000000000000", "string": "0E-6177", "match_string": "0E-6176" }, { "description": "[decq414] clamped zeros... (Clamped)", "subject": "180000001364000000000000000000000000000000FE5F00", "string": "0E+6112", "match_string": "0E+6111" }, { "description": "[decq416] clamped zeros... (Clamped)", "subject": "180000001364000000000000000000000000000000FE5F00", "string": "0E+6144", "match_string": "0E+6111" }, { "description": "[decq418] clamped zeros... (Clamped)", "subject": "180000001364000000000000000000000000000000FE5F00", "string": "0E+8000", "match_string": "0E+6111" }, { "description": "[decq420] negative zeros (Clamped)", "subject": "180000001364000000000000000000000000000000008000", "string": "-0E-8000", "match_string": "-0E-6176" }, { "description": "[decq421] negative zeros (Clamped)", "subject": "180000001364000000000000000000000000000000008000", "string": "-0E-6177", "match_string": "-0E-6176" }, { "description": "[decq434] clamped zeros... (Clamped)", "subject": "180000001364000000000000000000000000000000FEDF00", "string": "-0E+6112", "match_string": "-0E+6111" }, { "description": "[decq436] clamped zeros... (Clamped)", "subject": "180000001364000000000000000000000000000000FEDF00", "string": "-0E+6144", "match_string": "-0E+6111" }, { "description": "[decq438] clamped zeros... (Clamped)", "subject": "180000001364000000000000000000000000000000FEDF00", "string": "-0E+8000", "match_string": "-0E+6111" }, { "description": "[decq601] fold-down full sequence (Clamped)", "subject": "18000000136400000000000A5BC138938D44C64D31FE5F00", "string": "1E+6144", "match_string": "1.000000000000000000000000000000000E+6144" }, { "description": "[decq603] fold-down full sequence (Clamped)", "subject": "180000001364000000000081EFAC855B416D2DEE04FE5F00", "string": "1E+6143", "match_string": "1.00000000000000000000000000000000E+6143" }, { "description": "[decq605] fold-down full sequence (Clamped)", "subject": "1800000013640000000080264B91C02220BE377E00FE5F00", "string": "1E+6142", "match_string": "1.0000000000000000000000000000000E+6142" }, { "description": "[decq607] fold-down full sequence (Clamped)", "subject": "1800000013640000000040EAED7446D09C2C9F0C00FE5F00", "string": "1E+6141", "match_string": "1.000000000000000000000000000000E+6141" }, { "description": "[decq609] fold-down full sequence (Clamped)", "subject": "18000000136400000000A0CA17726DAE0F1E430100FE5F00", "string": "1E+6140", "match_string": "1.00000000000000000000000000000E+6140" }, { "description": "[decq611] fold-down full sequence (Clamped)", "subject": "18000000136400000000106102253E5ECE4F200000FE5F00", "string": "1E+6139", "match_string": "1.0000000000000000000000000000E+6139" }, { "description": "[decq613] fold-down full sequence (Clamped)", "subject": "18000000136400000000E83C80D09F3C2E3B030000FE5F00", "string": "1E+6138", "match_string": "1.000000000000000000000000000E+6138" }, { "description": "[decq615] fold-down full sequence (Clamped)", "subject": "18000000136400000000E4D20CC8DCD2B752000000FE5F00", "string": "1E+6137", "match_string": "1.00000000000000000000000000E+6137" }, { "description": "[decq617] fold-down full sequence (Clamped)", "subject": "180000001364000000004A48011416954508000000FE5F00", "string": "1E+6136", "match_string": "1.0000000000000000000000000E+6136" }, { "description": "[decq619] fold-down full sequence (Clamped)", "subject": "18000000136400000000A1EDCCCE1BC2D300000000FE5F00", "string": "1E+6135", "match_string": "1.000000000000000000000000E+6135" }, { "description": "[decq621] fold-down full sequence (Clamped)", "subject": "18000000136400000080F64AE1C7022D1500000000FE5F00", "string": "1E+6134", "match_string": "1.00000000000000000000000E+6134" }, { "description": "[decq623] fold-down full sequence (Clamped)", "subject": "18000000136400000040B2BAC9E0191E0200000000FE5F00", "string": "1E+6133", "match_string": "1.0000000000000000000000E+6133" }, { "description": "[decq625] fold-down full sequence (Clamped)", "subject": "180000001364000000A0DEC5ADC935360000000000FE5F00", "string": "1E+6132", "match_string": "1.000000000000000000000E+6132" }, { "description": "[decq627] fold-down full sequence (Clamped)", "subject": "18000000136400000010632D5EC76B050000000000FE5F00", "string": "1E+6131", "match_string": "1.00000000000000000000E+6131" }, { "description": "[decq629] fold-down full sequence (Clamped)", "subject": "180000001364000000E8890423C78A000000000000FE5F00", "string": "1E+6130", "match_string": "1.0000000000000000000E+6130" }, { "description": "[decq631] fold-down full sequence (Clamped)", "subject": "18000000136400000064A7B3B6E00D000000000000FE5F00", "string": "1E+6129", "match_string": "1.000000000000000000E+6129" }, { "description": "[decq633] fold-down full sequence (Clamped)", "subject": "1800000013640000008A5D78456301000000000000FE5F00", "string": "1E+6128", "match_string": "1.00000000000000000E+6128" }, { "description": "[decq635] fold-down full sequence (Clamped)", "subject": "180000001364000000C16FF2862300000000000000FE5F00", "string": "1E+6127", "match_string": "1.0000000000000000E+6127" }, { "description": "[decq637] fold-down full sequence (Clamped)", "subject": "180000001364000080C6A47E8D0300000000000000FE5F00", "string": "1E+6126", "match_string": "1.000000000000000E+6126" }, { "description": "[decq639] fold-down full sequence (Clamped)", "subject": "1800000013640000407A10F35A0000000000000000FE5F00", "string": "1E+6125", "match_string": "1.00000000000000E+6125" }, { "description": "[decq641] fold-down full sequence (Clamped)", "subject": "1800000013640000A0724E18090000000000000000FE5F00", "string": "1E+6124", "match_string": "1.0000000000000E+6124" }, { "description": "[decq643] fold-down full sequence (Clamped)", "subject": "180000001364000010A5D4E8000000000000000000FE5F00", "string": "1E+6123", "match_string": "1.000000000000E+6123" }, { "description": "[decq645] fold-down full sequence (Clamped)", "subject": "1800000013640000E8764817000000000000000000FE5F00", "string": "1E+6122", "match_string": "1.00000000000E+6122" }, { "description": "[decq647] fold-down full sequence (Clamped)", "subject": "1800000013640000E40B5402000000000000000000FE5F00", "string": "1E+6121", "match_string": "1.0000000000E+6121" }, { "description": "[decq649] fold-down full sequence (Clamped)", "subject": "1800000013640000CA9A3B00000000000000000000FE5F00", "string": "1E+6120", "match_string": "1.000000000E+6120" }, { "description": "[decq651] fold-down full sequence (Clamped)", "subject": "1800000013640000E1F50500000000000000000000FE5F00", "string": "1E+6119", "match_string": "1.00000000E+6119" }, { "description": "[decq653] fold-down full sequence (Clamped)", "subject": "180000001364008096980000000000000000000000FE5F00", "string": "1E+6118", "match_string": "1.0000000E+6118" }, { "description": "[decq655] fold-down full sequence (Clamped)", "subject": "1800000013640040420F0000000000000000000000FE5F00", "string": "1E+6117", "match_string": "1.000000E+6117" }, { "description": "[decq657] fold-down full sequence (Clamped)", "subject": "18000000136400A086010000000000000000000000FE5F00", "string": "1E+6116", "match_string": "1.00000E+6116" }, { "description": "[decq659] fold-down full sequence (Clamped)", "subject": "180000001364001027000000000000000000000000FE5F00", "string": "1E+6115", "match_string": "1.0000E+6115" }, { "description": "[decq661] fold-down full sequence (Clamped)", "subject": "18000000136400E803000000000000000000000000FE5F00", "string": "1E+6114", "match_string": "1.000E+6114" }, { "description": "[decq663] fold-down full sequence (Clamped)", "subject": "180000001364006400000000000000000000000000FE5F00", "string": "1E+6113", "match_string": "1.00E+6113" }, { "description": "[decq665] fold-down full sequence (Clamped)", "subject": "180000001364000A00000000000000000000000000FE5F00", "string": "1E+6112", "match_string": "1.0E+6112" } ] } bson-ruby-4.15.0/spec/spec_tests/data/decimal128/decimal128-6.json000066400000000000000000000060501423026727100242650ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "parseErrors": [ { "description": "Incomplete Exponent", "subject": "1e" }, { "description": "Exponent at the beginning", "subject": "E01" }, { "description": "Just a decimal place", "subject": "." }, { "description": "2 decimal places", "subject": "..3" }, { "description": "2 decimal places", "subject": ".13.3" }, { "description": "2 decimal places", "subject": "1..3" }, { "description": "2 decimal places", "subject": "1.3.4" }, { "description": "2 decimal places", "subject": "1.34." }, { "description": "Decimal with no digits", "subject": ".e" }, { "description": "2 signs", "subject": "+-32.4" }, { "description": "2 signs", "subject": "-+32.4" }, { "description": "2 negative signs", "subject": "--32.4" }, { "description": "2 negative signs", "subject": "-32.-4" }, { "description": "End in negative sign", "subject": "32.0-" }, { "description": "2 negative signs", "subject": "32.4E--21" }, { "description": "2 negative signs", "subject": "32.4E-2-1" }, { "description": "2 signs", "subject": "32.4E+-21" }, { "description": "Empty string", "subject": "" }, { "description": "leading white space positive number", "subject": " 1" }, { "description": "leading white space negative number", "subject": " -1" }, { "description": "trailing white space", "subject": "1 " }, { "description": "Invalid", "subject": "E" }, { "description": "Invalid", "subject": "invalid" }, { "description": "Invalid", "subject": "i" }, { "description": "Invalid", "subject": "in" }, { "description": "Invalid", "subject": "-in" }, { "description": "Invalid", "subject": "Na" }, { "description": "Invalid", "subject": "-Na" }, { "description": "Invalid", "subject": "1.23abc" }, { "description": "Invalid", "subject": "1.23abcE+02" }, { "description": "Invalid", "subject": "1.23E+0aabs2" } ] } bson-ruby-4.15.0/spec/spec_tests/data/decimal128/decimal128-7.json000066400000000000000000000311371423026727100242720ustar00rootroot00000000000000{ "description": "Decimal128", "bson_type": "0x13", "test_key": "d", "parseErrors": [ { "description": "[basx572] Near-specials (Conversion_syntax)", "subject": "-9Inf" }, { "description": "[basx516] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "-1-" }, { "description": "[basx533] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "0000.." }, { "description": "[basx534] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": ".0000." }, { "description": "[basx535] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "00..00" }, { "description": "[basx569] Near-specials (Conversion_syntax)", "subject": "0Inf" }, { "description": "[basx571] Near-specials (Conversion_syntax)", "subject": "-0Inf" }, { "description": "[basx575] Near-specials (Conversion_syntax)", "subject": "0sNaN" }, { "description": "[basx503] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "++1" }, { "description": "[basx504] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "--1" }, { "description": "[basx505] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "-+1" }, { "description": "[basx506] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "+-1" }, { "description": "[basx510] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": " +1" }, { "description": "[basx513] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": " + 1" }, { "description": "[basx514] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": " - 1" }, { "description": "[basx501] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "." }, { "description": "[basx502] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": ".." }, { "description": "[basx519] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "" }, { "description": "[basx525] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "e100" }, { "description": "[basx549] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "e+1" }, { "description": "[basx577] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": ".e+1" }, { "description": "[basx578] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": "+.e+1" }, { "description": "[basx581] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": "E+1" }, { "description": "[basx582] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": ".E+1" }, { "description": "[basx583] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": "+.E+1" }, { "description": "[basx579] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": "-.e+" }, { "description": "[basx580] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": "-.e" }, { "description": "[basx584] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": "-.E+" }, { "description": "[basx585] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": "-.E" }, { "description": "[basx589] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": "+.Inf" }, { "description": "[basx586] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": ".NaN" }, { "description": "[basx587] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": "-.NaN" }, { "description": "[basx545] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "ONE" }, { "description": "[basx561] Near-specials (Conversion_syntax)", "subject": "qNaN" }, { "description": "[basx573] Near-specials (Conversion_syntax)", "subject": "-sNa" }, { "description": "[basx588] some baddies with dots and Es and dots and specials (Conversion_syntax)", "subject": "+.sNaN" }, { "description": "[basx544] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "ten" }, { "description": "[basx527] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "u0b65" }, { "description": "[basx526] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "u0e5a" }, { "description": "[basx515] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "x" }, { "description": "[basx574] Near-specials (Conversion_syntax)", "subject": "xNaN" }, { "description": "[basx530] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": ".123.5" }, { "description": "[basx500] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1..2" }, { "description": "[basx542] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1e1.0" }, { "description": "[basx553] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1E+1.2.3" }, { "description": "[basx543] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1e123e" }, { "description": "[basx552] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1E+1.2" }, { "description": "[basx546] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1e.1" }, { "description": "[basx547] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1e1." }, { "description": "[basx554] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1E++1" }, { "description": "[basx555] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1E--1" }, { "description": "[basx556] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1E+-1" }, { "description": "[basx557] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1E-+1" }, { "description": "[basx558] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1E'1" }, { "description": "[basx559] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1E\"1" }, { "description": "[basx520] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1e-" }, { "description": "[basx560] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1E" }, { "description": "[basx548] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1ee" }, { "description": "[basx551] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1.2.1" }, { "description": "[basx550] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1.23.4" }, { "description": "[basx529] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "1.34.5" }, { "description": "[basx531] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "01.35." }, { "description": "[basx532] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "01.35-" }, { "description": "[basx518] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "3+" }, { "description": "[basx521] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "7e99999a" }, { "description": "[basx570] Near-specials (Conversion_syntax)", "subject": "9Inf" }, { "description": "[basx512] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "12 " }, { "description": "[basx517] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "12-" }, { "description": "[basx507] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "12e" }, { "description": "[basx508] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "12e++" }, { "description": "[basx509] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "12f4" }, { "description": "[basx536] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "111e*123" }, { "description": "[basx537] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "111e123-" }, { "description": "[basx540] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "111e1*23" }, { "description": "[basx538] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "111e+12+" }, { "description": "[basx539] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "111e1-3-" }, { "description": "[basx541] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "111E1e+3" }, { "description": "[basx528] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "123,65" }, { "description": "[basx523] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "7e12356789012x" }, { "description": "[basx522] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "subject": "7e123567890x" } ] } bson-ruby-4.15.0/spec/support/000077500000000000000000000000001423026727100161735ustar00rootroot00000000000000bson-ruby-4.15.0/spec/support/shared_examples.rb000066400000000000000000000063231423026727100216700ustar00rootroot00000000000000# Copyright (C) 2009-2020 MongoDB Inc. # # 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. shared_examples_for "a binary encoded string" do let(:binary_encoding) do Encoding.find(BSON::BINARY) end it "returns the string with binary encoding" do expect(encoded.encoding).to eq(binary_encoding) end end shared_examples_for "a bson element" do let(:element) do defined?(obj) ? obj : described_class.new end it "has the correct single byte BSON type" do expect(element.bson_type).to eq(type) end end shared_examples_for "a serializable bson element" do it "serializes to bson" do expect(obj.to_bson.to_s).to eq(bson) end end shared_examples_for "a deserializable bson element" do let(:io) do BSON::ByteBuffer.new(bson) end let(:result) do (defined?(klass) ? klass : described_class).from_bson(io) end it "deserializes from bson" do expect(result).to eq(obj) end end shared_examples_for "a JSON serializable object" do it "serializes the JSON from #as_json" do expect(object.to_json).to eq(object.as_json.to_json) end end shared_examples_for "immutable when frozen" do |block| context "when the document is frozen" do before do doc.freeze end it "raises a runtime error" do expect { block.call(doc) }.to raise_error(RuntimeError) end end end shared_examples_for "a document able to handle utf-8" do it "serializes and deserializes properly" do expect( BSON::Document.from_bson(BSON::ByteBuffer.new(document.to_bson.to_s)) ).to eq(document) end end shared_examples_for "a class which converts to Time" do it "shares BSON type with Time" do expect(described_class.new.bson_type).to eq(Time::BSON_TYPE) end end shared_examples_for "a validated BSON key" do context "when the string is valid" do context "when the string has no invalid characters" do let(:string) do "testing" end it "returns the key" do expect(validated).to eq(string) end end context "when the string contains a $" do let(:string) do "te$ting" end it "returns the key" do expect(validated).to eq(string) end end end context "when the string is invalid" do context "when the string starts with $" do let(:string) do "$testing" end it "raises an exception" do expect { validated }.to raise_error(BSON::String::IllegalKey) end end context "when the string contains a ." do let(:string) do "testing.testing" end it "raises an exception" do expect { validated }.to raise_error(BSON::String::IllegalKey) end end end end bson-ruby-4.15.0/spec/support/spec_config.rb000066400000000000000000000005061423026727100210000ustar00rootroot00000000000000require 'singleton' class SpecConfig include Singleton COMPACTION_CHANCE = 0.001 def active_support? %w(1 true yes).include?(ENV['WITH_ACTIVE_SUPPORT']) || ENV['WITH_ACTIVE_SUPPORT'] =~ /[0-9]/ && ENV['WITH_ACTIVE_SUPPORT'] != '0' end def compact? %w(1 true yes).include?(ENV['COMPACT']) end end bson-ruby-4.15.0/spec/support/utils.rb000066400000000000000000000006321423026727100176610ustar00rootroot00000000000000module Utils # JRuby chokes when strings like "\xfe\x00\xff", which are not valid UTF-8, # appear in the source. Use this method to build such strings. # char_array is an array of byte values to use for the string. module_function def make_byte_string(char_array, encoding = 'BINARY') char_array.map do |char| char.chr.force_encoding('BINARY') end.join.force_encoding(encoding) end end bson-ruby-4.15.0/src/000077500000000000000000000000001423026727100143145ustar00rootroot00000000000000bson-ruby-4.15.0/src/main/000077500000000000000000000000001423026727100152405ustar00rootroot00000000000000bson-ruby-4.15.0/src/main/org/000077500000000000000000000000001423026727100160275ustar00rootroot00000000000000bson-ruby-4.15.0/src/main/org/bson/000077500000000000000000000000001423026727100167705ustar00rootroot00000000000000bson-ruby-4.15.0/src/main/org/bson/ByteBuf.java000066400000000000000000000520401423026727100211740ustar00rootroot00000000000000/* * Copyright (C) 2015-2020 MongoDB Inc. * * 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. */ package org.bson; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; import org.jcodings.Encoding; import org.jcodings.EncodingDB; import org.jcodings.specific.UTF8Encoding; import org.jruby.Ruby; import org.jruby.RubyBignum; import org.jruby.RubyClass; import org.jruby.RubyException; import org.jruby.RubyFloat; import org.jruby.RubyFixnum; import org.jruby.RubyInteger; import org.jruby.RubyNumeric; import org.jruby.RubyObject; import org.jruby.RubyString; import org.jruby.RubySymbol; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.Block; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; import static java.lang.String.format; /** * Provides native extensions around boolean operations. * * @since 4.0.0 */ public class ByteBuf extends RubyObject { /** * Constant for a null byte. */ private static byte NULL_BYTE = 0x00; /** * The default size of the buffer. */ private static int DEFAULT_SIZE = 1024; /** * The UTF-8 String. */ private static String UTF8 = "UTF-8".intern(); /** * Constant for UTF-8 encoding. */ private static Encoding UTF_8 = EncodingDB.getEncodings().get(UTF8.getBytes()).getEncoding(); /** * The modes for the buffer. */ private enum Mode { READ, WRITE } /** * The wrapped byte buffer. */ private ByteBuffer buffer; /** * The current buffer mode. */ private Mode mode; /** * The current position while reading. */ private int readPosition = 0; /** * The current position while writing. */ private int writePosition = 0; /** * The size of an unsigned 32-bit integer: 2^32 - 1 */ private static long UINT32_MAX = 4294967295L; /** * Instantiate the ByteBuf - this is #allocate in Ruby. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ public ByteBuf(final Ruby runtime, final RubyClass rubyClass) { super(runtime, rubyClass); } /** * Initialize an empty buffer. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "initialize") public IRubyObject intialize() { this.buffer = ByteBuffer.allocate(DEFAULT_SIZE).order(ByteOrder.LITTLE_ENDIAN); this.mode = Mode.WRITE; return null; } /** * Instantiate the buffer with bytes. * * @param value The bytes to instantiate with. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "initialize") public IRubyObject initialize(final RubyString value) { this.buffer = ByteBuffer.wrap(value.getBytes()).order(ByteOrder.LITTLE_ENDIAN); this.mode = Mode.READ; return null; } /** * Get the total length of the buffer. * * @author Durran Jordan * @since 2015.09.29 * @version 4.0.0 */ @JRubyMethod(name = "length") public RubyFixnum getLength(ThreadContext context) { return new RubyFixnum(context.runtime, getLengthInternal()); } private int getLengthInternal() { if (this.mode == Mode.WRITE) { return this.writePosition; } else { return this.buffer.remaining(); } } /** * Get the read position of the buffer. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "read_position") public RubyFixnum getReadPosition(ThreadContext context) { return new RubyFixnum(context.runtime, this.readPosition); } /** * Get the write position of the buffer. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "write_position") public RubyFixnum getWritePosition(ThreadContext context) { return new RubyFixnum(context.runtime, this.writePosition); } /** * Reset the read position to the beginning of the byte buffer. * * @author Emily Stolfo * @since 2016.01.19 * @version 4.0.1 */ @JRubyMethod(name = "rewind!") public ByteBuf rewind() { this.buffer.rewind(); this.mode = Mode.READ; this.readPosition = 0; return this; } /** * Convert the byte buffer to a string of the bytes. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "to_s") public RubyString toRubyString(ThreadContext context) { ByteBuffer buffer_copy = this.buffer.duplicate(); if (this.mode == Mode.WRITE) { buffer_copy.flip(); } int length = this.getLengthInternal(); byte[] bytes = new byte[length]; buffer_copy.get(bytes, 0, length); return RubyString.newString(context.runtime, bytes); } /** * Get a single byte from the buffer. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "get_byte") public RubyString getByte() { ensureBsonRead(); RubyString string = RubyString.newString(getRuntime(), new byte[] { this.buffer.get() }); this.readPosition += 1; return string; } /** * Get the supplied number of bytes from the buffer. * * @param value The number of bytes to read. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "get_bytes") public RubyString getBytes(final IRubyObject value) { ensureBsonRead(); int length = RubyNumeric.fix2int((RubyFixnum) value); byte[] bytes = new byte[length]; ByteBuffer buff = this.buffer.get(bytes); RubyString string = RubyString.newString(getRuntime(), bytes); this.readPosition += length; return string; } /** * Get a CString from the buffer. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "get_cstring") public RubyString getCString(ThreadContext context) { ensureBsonRead(); ByteArrayOutputStream bytes = new ByteArrayOutputStream(); byte next = NULL_BYTE; while((next = this.buffer.get()) != NULL_BYTE) { bytes.write(next); } RubyString string = getUTF8String(context, bytes.toByteArray()); this.readPosition += (bytes.size() + 1); return string; } /** * Get the 16 bytes representing the decimal128 from the buffer. * * @author Emily Stolfo * @since 2016.03.24 * @version 4.1.0 */ @JRubyMethod(name = "get_decimal128_bytes") public RubyString getDecimal128Bytes() { return getBytes(new RubyFixnum(getRuntime(), 16)); } /** * Get a double from the buffer. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "get_double") public RubyFloat getDouble() { ensureBsonRead(); RubyFloat doubl = new RubyFloat(getRuntime(), this.buffer.getDouble()); this.readPosition += 8; return doubl; } /** * Get a 32 bit integer from the buffer. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "get_int32") public RubyFixnum getInt32() { ensureBsonRead(); RubyFixnum int32 = new RubyFixnum(getRuntime(), this.buffer.getInt()); this.readPosition += 4; return int32; } /** * Get a 32 bit integer from the buffer. * */ @JRubyMethod(name = "get_uint32") public RubyFixnum getUInt32() { ensureBsonRead(); long temp = this.buffer.getInt(); // if temp is a negative number, convert to an unsigned 32 bit number // by adding 2^32. For example if temp is -1, convert it to 2^32-1. if (temp < 0) { temp += UINT32_MAX + 1; } RubyFixnum int32 = new RubyFixnum(getRuntime(), temp); this.readPosition += 4; return int32; } /** * Get a UTF-8 string from the buffer. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "get_string") public RubyString getString(ThreadContext context) { ensureBsonRead(); int length = this.buffer.getInt(); this.readPosition += 4; byte[] stringBytes = new byte[length]; this.buffer.get(stringBytes); if (stringBytes.length != length) { RubyClass cls = context.runtime.getClass("BSON::Error::BSONDecodeError"); RubyString msg = RubyString.newString(context.runtime, String.format("Failed to read %d bytes: %d bytes read", length, stringBytes.length)); throw ((RubyException) cls.newInstance(context, msg, Block.NULL_BLOCK)).toThrowable(); } if (stringBytes[stringBytes.length-1] != 0) { RubyClass cls = context.runtime.getClass("BSON::Error::BSONDecodeError"); RubyString msg = RubyString.newString(context.runtime, "Last byte was not null: " + String.format("%02X", stringBytes[length-1])); throw ((RubyException) cls.newInstance(context, msg, Block.NULL_BLOCK)).toThrowable(); } byte[] bytes = Arrays.copyOfRange(stringBytes, 0, stringBytes.length - 1); RubyString string = getUTF8String(context, bytes); this.readPosition += length; return string; } /** * Get a 64 bit integer from the buffer. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "get_int64") public RubyFixnum getInt64() { ensureBsonRead(); RubyFixnum int64 = new RubyFixnum(getRuntime(), this.buffer.getLong()); this.readPosition += 8; return int64; } /** * Put a single byte onto the buffer. * * @param value The byte to write. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "put_byte") public ByteBuf putByte(ThreadContext context, final IRubyObject value) { RubyString string; try { string = (RubyString) value; } catch (ClassCastException e) { throw context.runtime.newArgumentError(e.toString()); } if (string.strLength() != 1) { throw context.runtime.newArgumentError("put_byte requires a string of length 1"); } ensureBsonWrite(1); this.buffer.put(string.getBytes()[0]); this.writePosition += 1; return this; } /** * Put raw bytes onto the buffer. * * @param value The bytes to write. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "put_bytes") public ByteBuf putBytes(ThreadContext context, final IRubyObject value) { RubyString string; try { string = (RubyString) value; } catch (ClassCastException e) { throw context.runtime.newArgumentError(e.toString()); } byte[] bytes = string.getBytes(); ensureBsonWrite(bytes.length); this.buffer.put(bytes); this.writePosition += bytes.length; return this; } /** * Put a UTF-8 string onto the buffer. * * @param value The UTF-8 string to write. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "put_string") public ByteBuf putString(ThreadContext context, final IRubyObject value) throws UnsupportedEncodingException { RubyString string = (RubyString) value; RubyString encodedString = convertToUtf8(context, string); String javaString = encodedString.asJavaString(); return putJavaString(javaString); } /** * Put a cstring onto the buffer. * * @param value The cstring to write. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "put_cstring") public ByteBuf putCString(ThreadContext context, final IRubyObject value) throws UnsupportedEncodingException { if (value instanceof RubyFixnum) { RubyString str = ((RubyFixnum) value).to_s(); String string = str.asJavaString(); this.writePosition += writeCharacters(string); } else if (value instanceof RubyString || value instanceof RubySymbol) { RubyString string; if (value instanceof RubySymbol) { string = (RubyString) ((RubySymbol) value).to_s(context); } else { string = (RubyString) value; } string = convertToUtf8(context, string); String javaString = string.asJavaString(); verifyNoNulls(javaString); this.writePosition += writeCharacters(javaString); } else { throw getRuntime().newTypeError(format("Invalid type for put_cstring: %s", value)); } return this; } /** * Put a symbol onto the buffer. * * @param value The UTF-8 string to write. * * @author Ben Lewis * @since 2017.04.19 * @version 4.2.2 */ @JRubyMethod(name = "put_symbol") public ByteBuf putSymbol(ThreadContext context, final IRubyObject value) throws UnsupportedEncodingException { RubyString str = (RubyString) ((RubySymbol) value).to_s(context); return putString(context, str); } /** * Put a 32 bit integer onto the buffer. * * @param value The integer to write. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "put_int32") public ByteBuf putInt32(ThreadContext context, IRubyObject value) { if (value instanceof RubyFloat) { value = ((RubyFloat) value).truncate(context); } ensureBsonWrite(4); this.buffer.putInt(RubyNumeric.fix2int((RubyFixnum) value)); this.writePosition += 4; return this; } /** * Put an unsigned 32 bit integer onto the buffer. * * @param value The integer to write. * */ @JRubyMethod(name = "put_uint32") public ByteBuf putUInt32(ThreadContext context, IRubyObject value) { if (value instanceof RubyFloat) { throw getRuntime().newArgumentError("put_uint32: incorrect type: float, expected: integer"); } ensureBsonWrite(4); long temp = RubyNumeric.fix2long((RubyFixnum) value); if (temp > UINT32_MAX || temp < 0) { throw getRuntime().newRangeError(format("Number %d is out of range [0, 2^32)", temp)); } // When a long is cast to an int, Java appears to take the bits of the long and // use them as is for the int value. For example, if temp is 2^32-1, (int) temp // would be -1, and if temp is 2^31, (int) temp would be -2^31. this.buffer.putInt((int) temp); this.writePosition += 4; return this; } /** * Put a 64 bit integer onto the buffer. * * @param value The integer to write. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "put_int64") public ByteBuf putInt64(ThreadContext context, IRubyObject value) { if (value instanceof RubyFloat) { value = ((RubyFloat) value).truncate(context); } ensureBsonWrite(8); this.buffer.putLong(((RubyInteger) value).getLongValue()); this.writePosition += 8; return this; } /** * Put a double onto the buffer. * * @param value the double to write. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "put_double") public ByteBuf putDouble(ThreadContext context, final IRubyObject value) { ensureBsonWrite(8); RubyFloat float_value; try { if (value instanceof RubyInteger) { float_value = (RubyFloat) ((RubyInteger) value).to_f(); } else { float_value = (RubyFloat) value; } } catch (ClassCastException e) { throw context.runtime.newTypeError(e.toString()); } this.buffer.putDouble(float_value.getDoubleValue()); this.writePosition += 8; return this; } /** * Put the decimal128 high and low bits on to the buffer. * * @param low The low 64 bits. * @param high The high 64 bits. * * @author Emily Stolfo * @since 2016.03.24 * @version 4.1.0 */ @JRubyMethod(name = "put_decimal128") public ByteBuf putDecimal128(final IRubyObject low, final IRubyObject high) { ensureBsonWrite(16); BigInteger bigLow; BigInteger bigHigh; if (low instanceof RubyBignum) { bigLow = ((RubyBignum) low).getBigIntegerValue(); } else { bigLow = ((RubyFixnum) low).getBigIntegerValue(); } if (high instanceof RubyBignum) { bigHigh = ((RubyBignum) high).getBigIntegerValue(); } else { bigHigh = ((RubyFixnum) high).getBigIntegerValue(); } this.buffer.putLong(bigLow.longValue()); this.writePosition += 8; this.buffer.putLong(bigHigh.longValue()); this.writePosition += 8; return this; } /** * Replace a 32 bit integer at the provided position in the buffer. * * @param position The position to replace at. * @param value The value to replace with. * * @author Durran Jordan * @since 2015.09.26 * @version 4.0.0 */ @JRubyMethod(name = "replace_int32") public ByteBuf replaceInt32(final IRubyObject position, final IRubyObject value) { int i = RubyNumeric.fix2int((RubyFixnum) position); int int32 = RubyNumeric.fix2int((RubyFixnum) value); if (i < 0) { throw getRuntime().newArgumentError(format("Position given to replace_int32 cannot be negative: %d", i)); } if (this.writePosition < 4) { throw getRuntime().newArgumentError(format("Buffer does not have enough data to use replace_int32")); } if (i > this.writePosition - 4) { throw getRuntime().newArgumentError(format("Position given to replace_int32 is out of bounds: %d", i)); } this.buffer.putInt(i, int32); return this; } private void write(byte b) { ensureBsonWrite(1); this.buffer.put(b); } private int writeCharacters(final String string) { int len = string.length(); int total = 0; for (int i = 0; i < len;) { int c = Character.codePointAt(string, i); if (c < 0x80) { write((byte) c); total += 1; } else if (c < 0x800) { write((byte) (0xc0 + (c >> 6))); write((byte) (0x80 + (c & 0x3f))); total += 2; } else if (c < 0x10000) { write((byte) (0xe0 + (c >> 12))); write((byte) (0x80 + ((c >> 6) & 0x3f))); write((byte) (0x80 + (c & 0x3f))); total += 3; } else { write((byte) (0xf0 + (c >> 18))); write((byte) (0x80 + ((c >> 12) & 0x3f))); write((byte) (0x80 + ((c >> 6) & 0x3f))); write((byte) (0x80 + (c & 0x3f))); total += 4; } i += Character.charCount(c); } write((byte) 0); total++; return total; } private ByteBuf putJavaString(final String string) { ensureBsonWrite(4); this.buffer.putInt(0); int length = writeCharacters(string); this.buffer.putInt(this.buffer.position() - length - 4, length); this.writePosition += (length + 4); return this; } private void ensureBsonRead() { if (this.mode == Mode.WRITE) { this.buffer.flip(); this.mode = Mode.READ; } } private void ensureBsonWrite(int length) { if (this.mode == Mode.READ) { this.buffer.flip(); this.mode = mode.WRITE; } if (length > this.buffer.remaining()) { int size = (this.buffer.position() + length) * 2; ByteBuffer newBuffer = ByteBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN); if (this.buffer.position() > 0) { byte [] existing = new byte[this.buffer.position()]; this.buffer.rewind(); this.buffer.get(existing); newBuffer.put(existing); } this.buffer = newBuffer; } } private RubyString getUTF8String(ThreadContext context, final byte[] bytes) { // This call appears to not validate that the byte sequence is valid UTF-8 RubyString str = RubyString.newString(context.runtime, bytes, 0, bytes.length, UTF_8); // ... hence validate manually: convertToUtf8(context, str); return str; } /** * Converts +string+ to UTF-8 encoding. If +string+ is already in UTF-8, * verifies that +string+ contains valid byte sequences by encoding in * another encoding (currently UTF-16). */ private RubyString convertToUtf8(ThreadContext context, RubyString string) { RubyString encodedString; if (string.getEncoding() == UTF8Encoding.INSTANCE) { // If the value is already in UTF-8, encoding it to UTF-8 is a noop. // But we also want to validate the bytes for being a valid UTF-8 sequence. // Do this by encoding the string to UTF-16 for the time being. RubyString utf16 = RubyString.newString(context.runtime, "UTF-16"); string.encode(context, utf16); encodedString = string; } else { RubyString utf8 = RubyString.newString(context.runtime, "UTF-8"); encodedString = (RubyString) string.encode(context, utf8); } return encodedString; } private void verifyNoNulls(String string) { int len = string.length(); for (int i = 0; i < len;) { int c = Character.codePointAt(string, i); if (c == 0) { throw getRuntime().newArgumentError(format("String %s contains null bytes", string)); } i += Character.charCount(c); } } } bson-ruby-4.15.0/src/main/org/bson/GeneratorExtension.java000066400000000000000000000065511423026727100234650ustar00rootroot00000000000000/* * Copyright (C) 2009-2020 MongoDB Inc. * * 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. */ package org.bson; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyInteger; import org.jruby.RubyModule; import org.jruby.RubyString; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.builtin.IRubyObject; /** * Provides native extensions around object id generator operations. * * @since 2.0.0 */ public class GeneratorExtension { /** * Constant for the ObjectId module name. * * @since 2.0.0 */ private static final String OBJECT_ID = "ObjectId".intern(); /** * Constant for the Generator class name. * * @since 2.0.0 */ private static final String GENERATOR = "Generator".intern(); /** * The thread safe counter for the last 3 object id bytes. * * @since 2.0.0 */ private static AtomicInteger counter = new AtomicInteger(new Random().nextInt()); /** * The integer representation of the unique machine id. * * @since 2.0.0 */ private static int machineId = new MachineId().value(); /** * Load the method definitions into the generator class. * * @param bson The bson module to define the methods under. * * @since 2.0.0 */ public static void extend(final RubyModule bson) { RubyClass objectId = bson.fastGetClass(OBJECT_ID); RubyClass generator = objectId.fastGetClass(GENERATOR); generator.defineAnnotatedMethods(GeneratorExtension.class); } /** * Get the next object id in the sequence. * * @param generator The generator instance. * * @return The encoded bytes. * * @since 2.0.0 */ @JRubyMethod(name = "next") public static IRubyObject next(final IRubyObject generator) { return nextObjectId(generator, (int) System.currentTimeMillis() / 1000); } /** * Get the next object id in the sequence. * * @param generator The generator instance. * @param time The time to generate at. * * @return The encoded bytes. * * @since 2.0.0 */ @JRubyMethod(name = "next") public static IRubyObject next(final IRubyObject generator, final IRubyObject time) { return nextObjectId(generator, (int) ((RubyInteger) time).getLongValue() / 1000); } /** * Generate the next object id in the sequence. * * @param generator The object id generator. * @param time The time in seconds. * * @return The object id raw bytes. * * @since 2.0.0 */ private static IRubyObject nextObjectId(final IRubyObject generator, final int time) { final ByteBuffer buffer = ByteBuffer.allocate(12).order(ByteOrder.BIG_ENDIAN); buffer.putInt(time).putInt(machineId).putInt(counter.getAndIncrement()); return RubyString.newString(generator.getRuntime(), buffer.array()); } } bson-ruby-4.15.0/src/main/org/bson/MachineId.java000066400000000000000000000050311423026727100214530ustar00rootroot00000000000000/* * Copyright (C) 2009-2020 MongoDB Inc. * * 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. */ package org.bson; import java.lang.management.ManagementFactory; import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; import java.util.Random; /** * Encapsulates behaviour around finding a unique machine id for an object id. * * @since 2.0.0 */ public class MachineId { /** * The value of the id. * * @since 2.0.0 */ private int value; /** * Instantiate the new machine id. * * @since 2.0.0 */ public MachineId() { this.value = generateMachineId() | generateProcessId(); } /** * Get the integer value of the machine id. * * @return The integer for the machine id. * * @since 2.0.0 */ public int value() { return value; } /** * Generate the identifier for the machine. * * @return The machine id. * * @since 2.0.0 */ private int generateMachineId() { try { return networkInterfaces(); } catch (SocketException error) { return new Random().nextInt() << 16; } } /** * Generate the identifier for the pid. * * @return The process id. * * @since 2.0.0 */ private int generateProcessId() { String processId = new String(); int pid = ManagementFactory.getRuntimeMXBean().getName().hashCode(); int loader = System.identityHashCode(MachineId.class.getClassLoader()); processId += Integer.toHexString(pid); processId += Integer.toHexString(loader); return processId.hashCode() & 0xFFFF; } /** * Get the generated integer for all the known network interfaces of the machine. * * @return The network interfaces. * * @since 2.0.0 */ private int networkInterfaces() throws SocketException { String machineId = new String(); Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { machineId += interfaces.nextElement().toString(); } return machineId.hashCode() & 0xFFFF; } } bson-ruby-4.15.0/src/main/org/bson/NativeService.java000066400000000000000000000036151423026727100224070ustar00rootroot00000000000000/* * Copyright (C) 2009-2020 MongoDB Inc. * * 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. */ package org.bson; import java.io.IOException; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyModule; import org.jruby.runtime.load.BasicLibraryService; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.builtin.IRubyObject; /** * The native implementation of various extensions. * * @since 2.0.0 */ public class NativeService implements BasicLibraryService { /** * Constant for the BSON module name. * * @since 2.0.0 */ private final String BSON = "BSON".intern(); /** * Constant for the BSON module name. * * @since 2.0.0 */ private final String BYTE_BUF = "ByteBuff".intern(); /** * Loads the native extension into the JRuby runtime. * * @param runtime The Ruby runtime. * * @return Always returns true if no exception. * * @since 2.0.0 */ public boolean basicLoad(final Ruby runtime) throws IOException { RubyModule bson = runtime.fastGetModule(BSON); GeneratorExtension.extend(bson); RubyClass byteBuffer = bson.defineClassUnder("ByteBuffer", runtime.getObject(), new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) { return new ByteBuf(runtime, rubyClass); } }); byteBuffer.defineAnnotatedMethods(ByteBuf.class); return true; } }