pax_global_header00006660000000000000000000000064150742026420014514gustar00rootroot0000000000000052 comment=f0387e3f618a98e92a9b047945cf21f47b92b5b4 bson-ruby-5.2.0/000077500000000000000000000000001507420264200134405ustar00rootroot00000000000000bson-ruby-5.2.0/.evergreen/000077500000000000000000000000001507420264200155005ustar00rootroot00000000000000bson-ruby-5.2.0/.evergreen/config.yml000066400000000000000000000303641507420264200174760ustar00rootroot00000000000000# GENERATED FILE - DO NOT EDIT. # Run ./.evergreen/update-evergreen-configs to regenerate this file. # ----------------------------------------------- # .evergreen/config/settings.yml.erb # ----------------------------------------------- # 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 # ----------------------------------------------- # .evergreen/config/functions.yml.erb # ----------------------------------------------- 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 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 test results": - command: attach.xunit_results params: file: ./src/tmp/rspec.xml "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: - func: "upload mo artifacts" - func: "upload test results" - func: "cleanup" tasks: - name: "test" commands: - func: "run tests" # ----------------------------------------------- # .evergreen/config/axes.yml.erb # ----------------------------------------------- axes: - id: "all-os" display_name: OS values: - id: debian display_name: "Debian 12" run_on: debian12-small variables: MACHINE: "debian12" - id: "ubuntu2404" display_name: "Ubuntu 24.04" run_on: ubuntu2404-small variables: MACHINE: "ubuntu2204" - id: "ubuntu2204" display_name: "Ubuntu 22.04" run_on: ubuntu2204-small variables: MACHINE: "ubuntu2204" - id: "ubuntu2004" display_name: "Ubuntu 20.04" run_on: ubuntu2004-small variables: MACHINE: "ubuntu2004" - id: "special-os" display_name: OS values: - id: "ubuntu2404-arm64" display_name: "Ubuntu 24.04 ARM64" run_on: ubuntu2404-arm64-small variables: MACHINE: ubuntu2404-arm64 - id: ruby display_name: Ruby Version values: - id: ruby-3.3 display_name: ruby-3.3 variables: RVM_RUBY: ruby-3.3 - id: ruby-3.2 display_name: ruby-3.2 variables: RVM_RUBY: ruby-3.2 - id: ruby-3.1 display_name: ruby-3.1 variables: RVM_RUBY: ruby-3.1 - id: ruby-3.0 display_name: ruby-3.0 variables: RVM_RUBY: ruby-3.0 - id: ruby-2.7 display_name: ruby-2.7 variables: RVM_RUBY: ruby-2.7 - id: jruby-10.0 display_name: jruby-10.0 variables: RVM_RUBY: jruby-10.0 - id: jruby-9.4 display_name: jruby-9.4 variables: RVM_RUBY: jruby-9.4 - id: jruby-9.3 display_name: jruby-9.3 variables: RVM_RUBY: jruby-9.3 - 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: "7.1" display_name: 7.1 variables: WITH_ACTIVE_SUPPORT: "~> 7.1.0" - id: "8.0" display_name: 8.0 variables: WITH_ACTIVE_SUPPORT: "~> 8.0.0" - id: "compact" display_name: GC.compact values: - id: "on" display_name: with GC.compact variables: COMPACT: true # ----------------------------------------------- # .evergreen/config/variants.yml.erb # ----------------------------------------------- buildvariants: - matrix_name: "mri-latest" matrix_spec: { ruby: ruby-3.3, all-os: '*' } display_name: "${ruby}, ${all-os}" tasks: - name: "test" - matrix_name: "mri-sample" matrix_spec: { ruby: ["ruby-2.7"], all-os: ubuntu2004 } display_name: "${ruby}, ${all-os}" tasks: - name: "test" - matrix_name: "activesupport-5-6" matrix_spec: ruby: ["ruby-3.0", "ruby-2.7"] all-os: ubuntu2004 as: [ '5.1', '5.2', '6.0', '6.1' ] display_name: "AS ${as} ${ruby}, ${all-os}" tasks: - name: "test" - matrix_name: "activesupport-7" matrix_spec: ruby: ruby-3.3 all-os: ubuntu2004 as: [ '7.0', '7.1' ] display_name: "AS ${as} ${ruby}, ${all-os}" tasks: - name: "test" - matrix_name: "activesupport-8" matrix_spec: ruby: ruby-3.3 all-os: ubuntu2004 as: '8.0' display_name: "AS ${as} ${ruby}, ${all-os}" tasks: - name: "test" - matrix_name: "special-os" matrix_spec: { ruby: ["ruby-3.2", "ruby-3.1"], special-os: '*' } display_name: "${ruby}, ${special-os}" tasks: - name: "test" - matrix_name: "jruby" matrix_spec: { ruby: ["jruby-10.0", "jruby-9.4", "jruby-9.3"], all-os: ubuntu2204 } display_name: "${ruby}, ${all-os}" tasks: - name: "test" - matrix_name: "compact" matrix_spec: ruby: ["ruby-3.3", "ruby-2.7"] all-os: ubuntu2004 compact: "on" display_name: "${ruby} with GC.compact" tasks: - name: "test" bson-ruby-5.2.0/.evergreen/config/000077500000000000000000000000001507420264200167455ustar00rootroot00000000000000bson-ruby-5.2.0/.evergreen/config/axes.yml.erb000066400000000000000000000037401507420264200212030ustar00rootroot00000000000000axes: - id: "all-os" display_name: OS values: - id: debian display_name: "Debian 12" run_on: debian12-small variables: MACHINE: "debian12" - id: "ubuntu2404" display_name: "Ubuntu 24.04" run_on: ubuntu2404-small variables: MACHINE: "ubuntu2204" - id: "ubuntu2204" display_name: "Ubuntu 22.04" run_on: ubuntu2204-small variables: MACHINE: "ubuntu2204" - id: "ubuntu2004" display_name: "Ubuntu 20.04" run_on: ubuntu2004-small variables: MACHINE: "ubuntu2004" - id: "special-os" display_name: OS values: - id: "ubuntu2404-arm64" display_name: "Ubuntu 24.04 ARM64" run_on: ubuntu2404-arm64-small variables: MACHINE: ubuntu2404-arm64 - id: ruby display_name: Ruby Version values: <% supported_rubies.each do |ruby| %> - id: <%= ruby %> display_name: <%= ruby %> variables: RVM_RUBY: <%= ruby %> <% end %> - 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: "7.1" display_name: 7.1 variables: WITH_ACTIVE_SUPPORT: "~> 7.1.0" - id: "8.0" display_name: 8.0 variables: WITH_ACTIVE_SUPPORT: "~> 8.0.0" - id: "compact" display_name: GC.compact values: - id: "on" display_name: with GC.compact variables: COMPACT: true bson-ruby-5.2.0/.evergreen/config/config.yml.erb000066400000000000000000000001511507420264200215010ustar00rootroot00000000000000<%= template 'settings' %> <%= template 'functions' %> <%= template 'axes' %> <%= template 'variants' %> bson-ruby-5.2.0/.evergreen/config/functions.yml.erb000066400000000000000000000154151507420264200222550ustar00rootroot00000000000000functions: "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 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 test results": - command: attach.xunit_results params: file: ./src/tmp/rspec.xml "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: - func: "upload mo artifacts" - func: "upload test results" - func: "cleanup" tasks: - name: "test" commands: - func: "run tests" bson-ruby-5.2.0/.evergreen/config/settings.yml.erb000066400000000000000000000013521507420264200221000ustar00rootroot00000000000000# 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 bson-ruby-5.2.0/.evergreen/config/variants.yml.erb000066400000000000000000000030431507420264200220660ustar00rootroot00000000000000buildvariants: - matrix_name: "mri-latest" matrix_spec: { ruby: <%= latest_mri_ruby %>, all-os: '*' } display_name: "${ruby}, ${all-os}" tasks: - name: "test" - matrix_name: "mri-sample" matrix_spec: { ruby: <%= sample_without_latest %>, all-os: ubuntu2004 } display_name: "${ruby}, ${all-os}" tasks: - name: "test" - matrix_name: "activesupport-5-6" matrix_spec: ruby: <%= older_rubies %> all-os: ubuntu2004 as: [ '5.1', '5.2', '6.0', '6.1' ] display_name: "AS ${as} ${ruby}, ${all-os}" tasks: - name: "test" - matrix_name: "activesupport-7" matrix_spec: ruby: <%= latest_mri_ruby %> all-os: ubuntu2004 as: [ '7.0', '7.1' ] display_name: "AS ${as} ${ruby}, ${all-os}" tasks: - name: "test" - matrix_name: "activesupport-8" matrix_spec: ruby: <%= latest_mri_ruby %> all-os: ubuntu2004 as: '8.0' display_name: "AS ${as} ${ruby}, ${all-os}" tasks: - name: "test" - matrix_name: "special-os" matrix_spec: { ruby: <%= recent_rubies - %w[ jruby-10.0 ] %>, special-os: '*' } display_name: "${ruby}, ${special-os}" tasks: - name: "test" - matrix_name: "jruby" matrix_spec: { ruby: <%= jrubies %>, all-os: ubuntu2204 } display_name: "${ruby}, ${all-os}" tasks: - name: "test" - matrix_name: "compact" matrix_spec: ruby: <%= sample_mri_rubies %> all-os: ubuntu2004 compact: "on" display_name: "${ruby} with GC.compact" tasks: - name: "test" bson-ruby-5.2.0/.evergreen/functions.sh000066400000000000000000000016621507420264200200510ustar00rootroot00000000000000set_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-5.2.0/.evergreen/run-tests.sh000066400000000000000000000014151507420264200200010ustar00rootroot00000000000000#!/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 # TODO: move this to shared/shlib/set_env.sh export JAVA_HOME="/opt/java/jdk21" export SOURCE_VERSION=21 export TARGET_VERSION=21 # END TODO export CI=1 echo "Running specs" bundle exec rake spec test_status=$? echo "TEST STATUS" echo ${test_status} kill_jruby exit ${test_status} bson-ruby-5.2.0/.evergreen/update-evergreen-configs000077500000000000000000000073231507420264200223230ustar00rootroot00000000000000#!/usr/bin/env ruby # frozen_string_literal: true require 'erb' require 'yaml' # A utility for building an evergreen config file. module ConfigProcessor extend self GENERATED_BANNER = <<~BANNER # GENERATED FILE - DO NOT EDIT. # Run ./.evergreen/update-evergreen-configs to regenerate this file. BANNER # Looks for a template in .evergreen/config with the given # base name, and 'yml.erb' as the extension. Processes that # template via ERB and writes the result to .evergreen with # the same basename, and a 'yml' extension. # # @param [ String ] name the name of the config to build. def build(name) output_path = File.join(__dir__, "#{name}.yml") File.write(output_path, GENERATED_BANNER + template(name, params: { header: false })) end # Reads the config template with the given name, processes it via # ERB, and returns the result. # # @param [ String ] name the (base) name of the template # # @return [ String ] the processed template def template(name, params: {}) source_file = template_path(name) header_for(source_file, params.fetch(:header, true)) + ERB.new(File.read(source_file), trim_mode: '<>').result(binding).strip + "\n" end # Returns the path to the config template with the given base name. # # @param [ String ] name the base name of the template # # @return [ String ] the path to the template with the given name. def template_path(name) File.join(__dir__, 'config', "#{name}.yml.erb") end # Returns a banner to be used as a header in the config file, # naming the given source file. This makes it easier to look at # the generated config file and know where to look if something # needs to be changed. # # @param [ String ] source_file the path to the source file # @param [ true | false ] generate_header whether to return a header # banner or not. # # @return [ String ] the header banner (or an empty string if # generate_header is false) def header_for(source_file, generate_header) return '' unless generate_header root_path = File.expand_path('..', __dir__) simplified_path = source_file.sub(/^#{root_path}\//, '') <<~HEADER # ----------------------------------------------- # #{simplified_path} # ----------------------------------------------- HEADER end # these are used for testing against a few recent ruby versions def recent_rubies @recent_rubies ||= %w[ ruby-3.2 ruby-3.1 jruby-10.0 ] end # the most recently released, stable version of Ruby (make sure this # version is being built by 10gen/mongo-ruby-toolchain) def latest_mri_ruby "ruby-3.3" end # this is a list of the most most recent 3.x and 2.x MRI ruby versions def sample_mri_rubies @sample_mri_rubies ||= %w[ ruby-3.3 ruby-2.7 ] end # same as `sample_mri_rubies`, but without the `latest_mri_ruby` entry. def sample_without_latest @sample_without_latest ||= sample_mri_rubies.reject { |v| v == latest_mri_ruby } end # as above, but including the most recent JRuby release def sample_rubies @sample_rubies ||= sample_mri_rubies + %w[ jruby-10.0 ] end # older Ruby versions provided by 10gen/mongo-ruby-toolchain def older_rubies @older_rubies ||= %w[ ruby-3.0 ruby-2.7 ] end # all supported JRuby versions provided by 10gen/mongo-ruby-toolchain def jrubies @jrubies ||= %w[ jruby-10.0 jruby-9.4 jruby-9.3 ] end # all supported MRI ruby versions def supported_mri_rubies @supported_mri_rubies ||= %w[ ruby-3.3 ruby-3.2 ruby-3.1 ruby-3.0 ruby-2.7 ] end # all supported ruby versions (MRI & JRuby) def supported_rubies @supported_rubies ||= supported_mri_rubies + jrubies end end ConfigProcessor.build 'config' bson-ruby-5.2.0/.github/000077500000000000000000000000001507420264200150005ustar00rootroot00000000000000bson-ruby-5.2.0/.github/CODEOWNERS000066400000000000000000000000241507420264200163670ustar00rootroot00000000000000* @mongodb/dbx-ruby bson-ruby-5.2.0/.github/workflows/000077500000000000000000000000001507420264200170355ustar00rootroot00000000000000bson-ruby-5.2.0/.github/workflows/bson-ruby.yml000066400000000000000000000027311507420264200215030ustar00rootroot00000000000000name: CI on: [push, pull_request, workflow_dispatch] jobs: rubocop: runs-on: ubuntu-latest env: CI: true steps: - uses: actions/checkout@v4 - name: Set up Ruby 3.4 uses: ruby/setup-ruby@v1 with: ruby-version: 3.4 bundler-cache: true - name: Run RuboCop run: bundle exec rubocop --parallel 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.7, '3.0', 3.1, 3.2, 3.3, 3.4, head ] include: - { os: windows , ruby: ucrt } exclude: - { os: windows , ruby: head } steps: - name: repo checkout uses: actions/checkout@v4 with: submodules: recursive - name: load ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} rubygems: latest bundler-cache: true - name: compile run: bundle exec rake compile - name: test timeout-minutes: 10 run: bundle exec rake spec bson-ruby-5.2.0/.github/workflows/cleanup.yml000066400000000000000000000022401507420264200212050ustar00rootroot00000000000000name: "Dry-Run Cleanup" run-name: "Dry Run Cleanup for ${{ github.ref }}" on: workflow_dispatch: inputs: confirm: description: Indicate whether you want this workflow to run (must be "true") required: true type: string tag: description: The name of the tag (and release) to clean up required: true type: string jobs: release: name: "Dry-Run Cleanup" environment: release runs-on: 'ubuntu-latest' if: ${{ inputs.confirm == 'true' }} permissions: # required for all workflows security-events: write # required to fetch internal or private CodeQL packs packages: read # only required for workflows in private repositories actions: read contents: write # required by the mongodb-labs/drivers-github-tools/setup@v2 step # also required by `rubygems/release-gem` id-token: write steps: - name: "Run the cleanup action" uses: mongodb-labs/drivers-github-tools/ruby/cleanup@v2 with: app_id: ${{ vars.APP_ID }} app_private_key: ${{ secrets.APP_PRIVATE_KEY }} tag: ${{ inputs.tag }} bson-ruby-5.2.0/.github/workflows/codeql.yml000066400000000000000000000036271507420264200210370ustar00rootroot00000000000000name: "CodeQL" on: [ push, pull_request ] jobs: analyze: name: Analyze (${{ matrix.language }}) # Runner size impacts CodeQL analysis time. To learn more, please see: # - https://gh.io/recommended-hardware-resources-for-running-codeql # - https://gh.io/supported-runners-and-hardware-resources # - https://gh.io/using-larger-runners (GitHub.com only) # Consider using larger runners or machines with greater resources for possible analysis time improvements. runs-on: 'ubuntu-latest' timeout-minutes: 360 permissions: # required for all workflows security-events: write # required to fetch internal or private CodeQL packs packages: read # only required for workflows in private repositories actions: read contents: read strategy: fail-fast: false matrix: include: - language: ruby build-mode: none - language: c build-mode: manual - language: java build-mode: none steps: - name: Checkout repository uses: actions/checkout@v4 with: submodules: true - name: Setup Ruby if: matrix.build-mode == 'manual' uses: ruby/setup-ruby@v1 with: ruby-version: '3.2' bundler-cache: true # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} config: | paths-ignore: - .evergreen - spec - perf - vendor - name: Manually build the native code if: matrix.build-mode == 'manual' run: | bundle exec rake compile - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" bson-ruby-5.2.0/.github/workflows/release.yml000066400000000000000000000046471507420264200212130ustar00rootroot00000000000000name: "BSON Release" run-name: "BSON Release for ${{ github.ref }}" on: # for auto-deploy when merging a release-candidate PR push: branches: - 'master' - '*-stable' # for manual release workflow_dispatch: inputs: pr: description: "The number of the merged release candidate PR" required: true env: GEM_NAME: bson PRODUCT_NAME: BSON for Ruby PRODUCT_ID: mongodb-ruby-driver permissions: # required for all workflows security-events: write # required to fetch internal or private CodeQL packs packages: read # only required for workflows in private repositories actions: read pull-requests: read contents: write # required by the mongodb-labs/drivers-github-tools/setup@v2 step # also required by `rubygems/release-gem` id-token: write jobs: check: name: "Check Release" runs-on: ubuntu-latest outputs: message: ${{ steps.check.outputs.message }} ref: ${{ steps.check.outputs.ref }} steps: - name: "Run the check action" id: check uses: mongodb-labs/drivers-github-tools/ruby/pr-check@v3 build: name: "Build Gems" needs: check environment: release runs-on: ubuntu-latest strategy: fail-fast: false matrix: ruby: [ 'ruby-3.2', 'jruby-9.4' ] steps: - name: "Run the build action" uses: mongodb-labs/drivers-github-tools/ruby/build@v3 with: app_id: ${{ vars.APP_ID }} app_private_key: ${{ secrets.APP_PRIVATE_KEY }} artifact: ${{ matrix.ruby }} gem_name: ${{ env.GEM_NAME }} ruby_version: ${{ matrix.ruby }} ref: ${{ needs.check.outputs.ref }} publish: name: Publish Gems needs: [ check, build ] environment: release runs-on: ubuntu-latest steps: - name: "Run the publish action" uses: mongodb-labs/drivers-github-tools/ruby/publish@v3 with: app_id: ${{ vars.APP_ID }} app_private_key: ${{ secrets.APP_PRIVATE_KEY }} aws_role_arn: ${{ secrets.AWS_ROLE_ARN }} aws_region_name: ${{ vars.AWS_REGION_NAME }} aws_secret_id: ${{ secrets.AWS_SECRET_ID }} dry_run: false gem_name: ${{ env.GEM_NAME }} product_name: ${{ env.PRODUCT_NAME }} product_id: ${{ env.PRODUCT_ID }} release_message: ${{ needs.check.outputs.message }} ref: ${{ needs.check.outputs.ref }} bson-ruby-5.2.0/.gitignore000066400000000000000000000004751507420264200154360ustar00rootroot00000000000000Gemfile.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-5.2.0/.gitmodules000066400000000000000000000001541507420264200156150ustar00rootroot00000000000000[submodule "spec/shared"] path = spec/shared url = https://github.com/mongodb-labs/mongo-ruby-spec-shared bson-ruby-5.2.0/.rspec000066400000000000000000000002601507420264200145530ustar00rootroot00000000000000--tty --colour <% if %w(1 true yes).include?(ENV['CI']&.downcase) %> --format RspecJunitFormatter --out tmp/rspec.xml --format 'Rfc::Riff' <% else %> --format Fuubar <% end %> bson-ruby-5.2.0/.rubocop.yml000066400000000000000000000034311507420264200157130ustar00rootroot00000000000000plugins: - rubocop-performance - rubocop-rake - rubocop-rspec AllCops: TargetRubyVersion: 2.6 NewCops: enable Exclude: - 'spec/shared/**/*' - 'tmp/**/*' - 'vendor/**/*' Bundler: Enabled: true Gemspec: Enabled: true Layout: Enabled: true Lint: Enabled: true Metrics: Enabled: true Naming: Enabled: true Performance: Enabled: true Rake: Enabled: true RSpec: Enabled: true Security: Exclude: - 'spec/**/*' Style: Enabled: true # -------------------------------------- # Cops below this line set intentionally # -------------------------------------- Bundler/OrderedGems: Enabled: false Gemspec/OrderedDependencies: Enabled: false Layout/SpaceInsideArrayLiteralBrackets: EnforcedStyle: space Layout/SpaceInsidePercentLiteralDelimiters: Enabled: false Metrics/ClassLength: Max: 200 Metrics/ModuleLength: Enabled: false Metrics/MethodLength: Max: 20 RSpec/BeforeAfterAll: Enabled: false # Ideally, we'd use this one, too, but our tests have not historically followed # this style and it's not worth changing right now, IMO RSpec/DescribeClass: Enabled: false Style/FetchEnvVar: Enabled: false Style/FormatString: Enabled: false RSpec/ImplicitExpect: EnforcedStyle: is_expected RSpec/MultipleExpectations: Enabled: false RSpec/MultipleMemoizedHelpers: Enabled: false RSpec/NestedGroups: Enabled: false Style/ClassVars: Enabled: false Style/Documentation: Exclude: - 'spec/**/*' Style/ModuleFunction: EnforcedStyle: extend_self Style/OptionalBooleanParameter: Enabled: false Style/ParallelAssignment: Enabled: false Style/TernaryParentheses: EnforcedStyle: require_parentheses_when_complex Style/TrailingCommaInArrayLiteral: Enabled: false Style/TrailingCommaInHashLiteral: Enabled: false bson-ruby-5.2.0/.yardopts000066400000000000000000000000451507420264200153050ustar00rootroot00000000000000lib/**/*.rb ext/bson/*.c -o yard-docsbson-ruby-5.2.0/CHANGELOG.md000066400000000000000000000157731507420264200152660ustar00rootroot00000000000000BSON 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-5.2.0/CONTRIBUTING.md000066400000000000000000000023641507420264200156760ustar00rootroot00000000000000Contributing ============ 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-5.2.0/Gemfile000066400000000000000000000017741507420264200147440ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all source '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', '<8.1' end gem 'concurrent-ruby', '1.3.4' gem 'ruby-prof', platforms: :mri gem 'byebug', platforms: :mri # https://github.com/jruby/jruby/wiki/UsingTheJRubyDebugger gem 'ruby-debug', platforms: :jruby # JRuby 9.3 reports RUBY_VERSION as 2.6, and the latest versions of Rubocop # wants 2.7 or higher. It enough to use rubocop only on MRI, so we can skip # it on JRuby. unless RUBY_PLATFORM =~ /java/ gem 'rubocop', '~> 1.75.5' gem 'rubocop-performance', '~> 1.25.0' gem 'rubocop-rake', '~> 0.7.1' gem 'rubocop-rspec', '~> 3.6.0' end end group :test do gem 'fuubar' gem 'rfc' gem "rspec_junit_formatter" end bson-ruby-5.2.0/LICENSE000066400000000000000000000250171507420264200144520ustar00rootroot00000000000000 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-5.2.0/NOTICE000066400000000000000000000000601507420264200143400ustar00rootroot00000000000000Ruby BSON Copyright (C) 2009-2013 MongoDB, Inc. bson-ruby-5.2.0/README.md000066400000000000000000000144351507420264200147260ustar00rootroot00000000000000BSON [![Gem Version][rubygems-img]][rubygems-url] [![Build Status][ghactions-img]][ghactions-url] ==== An implementation of the BSON specification in Ruby. Installation ------------ BSON can be installed via RubyGems: ``` > gem install bson ``` Or by adding it to your project's Gemfile: ```ruby gem 'bson' ``` ### Release Integrity Each release of the BSON library for Ruby after version 5.0.0 has been automatically built and signed using the team's GPG key. To verify the bson gem file: 1. [Download the GPG key](https://pgp.mongodb.com/ruby-driver.asc). 2. Import the key into your GPG keyring with `gpg --import ruby-driver.asc`. 3. Download the gem file (if you don't already have it). You can download it from RubyGems with `gem fetch bson`, or you can download it from the [releases page](https://github.com/mongodb/bson-ruby/releases) on GitHub. 4. Download the corresponding detached signature file from the [same release](https://github.com/mongodb/bson-ruby/releases). Look at the bottom of the release that corresponds to the gem file, under the 'Assets' list, for a `.sig` file with the same version number as the gem you wish to install. 5. Verify the gem with `gpg --verify bson-X.Y.Z.gem.sig bson-X.Y.Z.gem` (replacing `X.Y.Z` with the actual version number). You are looking for text like "Good signature from "MongoDB Ruby Driver Release Signing Key " in the output. If you see that, the signature was found to correspond to the given gem file. (Note that other output, like "This key is not certified with a trusted signature!", is related to *web of trust* and depends on how strongly you, personally, trust the `ruby-driver.asc` key that you downloaded from us. To learn more, see https://www.gnupg.org/gph/en/manual/x334.html) ### Why not use RubyGems' gem-signing functionality? RubyGems' own gem signing is problematic, most significantly because there is no established chain of trust related to the keys used to sign gems. RubyGems' own documentation admits that "this method of signing gems is not widely used" (see https://guides.rubygems.org/security/). Discussions about this in the RubyGems community have been off-and-on for more than a decade, and while a solution will eventually arrive, we have settled on using GPG instead for the following reasons: 1. Many of the other driver teams at MongoDB are using GPG to sign their product releases. Consistency with the other teams means that we can reuse existing tooling for our own product releases. 2. GPG is widely available and has existing tools and procedures for dealing with web of trust (though they are admittedly quite arcane and intimidating to the uninitiated, unfortunately). Ultimately, most users do not bother to verify gems, and will not be impacted by our choice of GPG over RubyGems' native method. Compatibility ------------- BSON is tested against MRI (2.7+) and JRuby (9.3+). Documentation ------------- Current documentation can be found [here](https://www.mongodb.com/docs/ruby-driver/current/bson-tutorials/). API Documentation ----------------- The [API Documentation](https://www.mongodb.com/docs/ruby-driver/master/api/) is located at mongodb.com/docs. BSON Specification ------------------ The [BSON specification](http://bsonspec.org) is at bsonspec.org. ## Bugs & Feature Requests To report a bug in the `bson` gem or request a feature: 1. Visit [our issue tracker](https://jira.mongodb.org/) and login (or create an account if you do not have one already). 2. Navigate to the [RUBY project](https://jira.mongodb.org/browse/RUBY). 3. Click 'Create Issue' and fill out all of the applicable form fields, making sure to select `BSON` in the _Component/s_ field. When creating an issue, please keep in mind that all information in JIRA for the RUBY project, as well as the core server (the SERVER project), is publicly visible. **PLEASE DO:** - Provide as much information as possible about the issue. - Provide detailed steps for reproducing the issue. - Provide any applicable code snippets, stack traces and log data. - Specify version numbers of the `bson` gem and/or Ruby driver and MongoDB server. **PLEASE DO NOT:** - Provide any sensitive data or server logs. - Report potential security issues publicly (see 'Security Issues' below). ## Security Issues If you have identified a potential security-related issue in the `bson` gem (or any other MongoDB product), please report it by following the [instructions here](https://www.mongodb.com/docs/manual/tutorial/create-a-vulnerability-report). ## Product Feature Requests To request a feature which is not specific to the `bson` gem, or which affects more than the `bson` gem and/or Ruby driver alone (for example, a feature which requires MongoDB server support), please submit your idea through the [MongoDB Feedback Forum](https://feedback.mongodb.com/forums/924286-drivers). ## Maintenance and Bug Fix Policy New library functionality is generally added in a backwards-compatible manner and results in new minor releases. Bug fixes are generally made on master first and are backported to the current minor library release. Exceptions may be made on a case-by-case basis, for example security fixes may be backported to older stable branches. Only the most recent minor release is officially supported. Customers should use the most recent release in their applications. 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 bson-ruby-5.2.0/Rakefile000066400000000000000000000105131507420264200151050ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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' if File.exist?('./spec/shared/lib/tasks/candidate.rake') load './spec/shared/lib/tasks/candidate.rake' end 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" ext.target_version = ENV['TARGET_VERSION'] if ENV['TARGET_VERSION'] ext.source_version = ENV['SOURCE_VERSION'] if ENV['SOURCE_VERSION'] 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 RSpec::Core::RakeTask.new(:rspec) desc 'Build the bson gem' task :build => [ :clean_all, *(jruby? ? :compile : nil) ] do command = [ 'gem', 'build' ] command << "--output=#{ENV['GEM_FILE_NAME']}" if ENV['GEM_FILE_NAME'] command << ENV['GEMSPEC'] || 'bson.gemspec' system(*command) end # `rake version` is used by the deployment system so get the release version # of the product beng deployed. It must do nothing more than just print the # product version number. desc 'Print the current version of the Ruby-BSON library' task :version do require 'bson/version' puts BSON::VERSION end task :clean_all => :clean do %w[ bson-ruby.jar bson_native.bundle bson_native.so bson_native.o ].each do |file| FileUtils.rm_f(File.join(File.dirname(__FILE__), 'lib', file)) end end task :spec => :compile do Rake::Task["rspec"].invoke end # overrides the default Bundler-provided `release` task, which also # builds the gem. Our release process assumes the gem has already # been built (and signed via GPG), so we just need `rake release` to # push the gem to rubygems. task :release do if ENV['GITHUB_ACTION'].nil? abort <<~WARNING `rake release` must be invoked from the `BSON Release` GitHub action, and must not be invoked locally. This ensures the gem is properly signed and distributed by the appropriate user. Note that it is the `rubygems/release-gem@v1` step in the `BSON Release` action that invokes this task. Do not rename or remove this task, or the release-gem step will fail. Reimplement this task with caution. NO GEMS were pushed to RubyGems. WARNING end # confirm: there ought to be two gems, one for MRI, and one for Java. These # will have been previously generated by the 'build' job. gems = Dir['*.gem'] if gems.length != 2 abort "Expected two gem files to be ready to release; got #{gems.inspect}" end gems.each do |gem| system 'gem', 'push', gem end end namespace :benchmark do task :prep do require_relative "perf/bench" end task ruby: [ :clean_all, 'benchmark:prep' ] do puts "Benchmarking pure Ruby..." benchmark! end task native: [ :compile, 'benchmark:prep' ] do puts "Benchmarking with native extensions..." benchmark! end namespace :decimal128 do task from_string: 'benchmark:prep' do puts "Benchmarking creating Decimal128 objects from a string" benchmark_decimal128_from_string! end task to_string: 'benchmark:prep' do puts "Benchmarking getting a string representation of a Decimal128" 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 require 'bson/version' out = File.join('yard-docs', BSON::VERSION) FileUtils.rm_rf(out) system "yardoc -o #{out} --title bson-#{BSON::VERSION}" end end bson-ruby-5.2.0/bson.gemspec000066400000000000000000000032321507420264200157460ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all lib = 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 = ["The MongoDB Ruby Team"] s.email = "dbx-ruby@mongodb.com" s.homepage = 'https://www.mongodb.com/docs/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://www.mongodb.com/docs/ruby-driver/current/tutorials/bson-v4/', 'homepage_uri' => 'https://www.mongodb.com/docs/ruby-driver/current/tutorials/bson-v4/', 'source_code_uri' => 'https://github.com/mongodb/bson-ruby' } 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 if RUBY_VERSION > '3.2.99' s.add_dependency 'base64' s.add_dependency 'bigdecimal' s.add_dependency 'ostruct' end s.test_files = Dir.glob('spec/**/*') s.require_path = 'lib' s.required_ruby_version = '>= 2.6' s.required_rubygems_version = '>= 1.3.6' end bson-ruby-5.2.0/ext/000077500000000000000000000000001507420264200142405ustar00rootroot00000000000000bson-ruby-5.2.0/ext/bson/000077500000000000000000000000001507420264200152015ustar00rootroot00000000000000bson-ruby-5.2.0/ext/bson/bson-endian.h000066400000000000000000000077051507420264200175600ustar00rootroot00000000000000/* * 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-5.2.0/ext/bson/bson-native.h000066400000000000000000000117771507420264200176140ustar00rootroot00000000000000/* * 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 #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 rb_bson_byte_buffer_put_array(VALUE self, VALUE array); 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); VALUE rb_bson_object_id_generator_reset_counter(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); #define BSON_OBJECT_ID_RANDOM_VALUE_LENGTH ( 5 ) uint8_t* pvt_get_object_id_random_value(); void pvt_init_rand(); void pvt_rand_buf(uint8_t* bytes, int len, int pid); int pvt_rand(); /** * The counter for incrementing object ids. */ extern uint32_t rb_bson_object_id_counter; extern VALUE rb_bson_registry; extern const rb_data_type_t rb_byte_buffer_data_type; extern VALUE _ref_str, _id_str, _db_str; bson-ruby-5.2.0/ext/bson/bytebuf.c000066400000000000000000000067021507420264200170120ustar00rootroot00000000000000/* * 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-5.2.0/ext/bson/endian.c000066400000000000000000000056561507420264200166170ustar00rootroot00000000000000/* * 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-5.2.0/ext/bson/extconf.rb000066400000000000000000000002201507420264200171660ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:disable all require 'mkmf' append_cflags(["-Wall", "-g", "-std=c99"]) create_makefile('bson_native') bson-ruby-5.2.0/ext/bson/init.c000066400000000000000000000301341507420264200163110ustar00rootroot00000000000000/* * 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; 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); rb_require("digest/md5"); 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_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) -> 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, 1); /* * 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, 1); /* * 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); rb_define_method(rb_bson_object_id_generator_class, "reset_counter", rb_bson_object_id_generator_reset_counter, -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); pvt_init_rand(); // Set the object id counter to a random 3-byte integer rb_bson_object_id_counter = pvt_rand() % 0xFFFFFF; rb_bson_registry = rb_const_get(rb_bson_module, rb_intern("Registry")); rb_gc_register_mark_object(rb_bson_registry); } bson-ruby-5.2.0/ext/bson/libbson-utf8.c000066400000000000000000000145661507420264200176750ustar00rootroot00000000000000#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-5.2.0/ext/bson/read.c000066400000000000000000000313001507420264200162550ustar00rootroot00000000000000/* * 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); static size_t pvt_strnlen(const 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; if (argc > 1) { rb_raise(rb_eArgError, "At most one argument is allowed"); } else if (argc > 0) { VALUE call_args[2]; call_args[0] = rb_buffer; Check_Type(argv[0], T_HASH); call_args[1] = argv[0]; #ifdef RB_PASS_KEYWORDS /* Ruby 2.7+ */ value = rb_funcallv_kw(klass, rb_intern("from_bson"), 2, call_args, RB_PASS_KEYWORDS); #else /* Ruby 2.6 and below */ value = rb_funcallv(klass, rb_intern("from_bson"), 2, call_args); #endif } else { 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 = Qnil; 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)pvt_strnlen(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)pvt_strnlen(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; } /** * Returns the length of the given string `str`. If no null-terminating byte * is present when `len` bytes have been scanned, then `len` is * returned. */ size_t pvt_strnlen(const byte_buffer_t *b) { const char *ptr = memchr(READ_PTR(b), '\0', READ_SIZE(b)); if (!ptr) rb_raise(rb_eRangeError, "string is too long (possibly not null-terminated)"); return (size_t)(ptr - READ_PTR(b)); } bson-ruby-5.2.0/ext/bson/util.c000066400000000000000000000167501507420264200163330ustar00rootroot00000000000000/* * 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]; /** * Holds a reference to the SecureRandom module, or Qnil if the modle is * not available. */ static VALUE pvt_SecureRandom = Qnil; /** * Indicates whether or not the SecureRandom module responds to the * `random_number` method (depends on Ruby version). */ static int pvt_has_random_number = 0; 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. * * Specification: * https://github.com/mongodb/specifications/blob/master/source/bson-objectid/objectid.md * * The ObjectID BSON type is a 12-byte value consisting of three different portions (fields): * * a 4-byte value representing the seconds since the Unix epoch in the highest order bytes, * * a 5-byte random number unique to a machine and process, * * a 3-byte counter, starting with a random value. */ VALUE rb_bson_object_id_generator_next(int argc, VALUE* args, VALUE self) { char bytes[12]; uint32_t time_component; uint8_t* random_component; uint32_t counter_component; VALUE timestamp; VALUE rb_bson_object_id_class; rb_bson_object_id_class = pvt_const_get_2("BSON", "ObjectId"); /* "Drivers SHOULD have an accessor method on an ObjectID class for * obtaining the timestamp value." */ timestamp = rb_funcall(rb_bson_object_id_class, rb_intern("timestamp"), 0); time_component = BSON_UINT32_TO_BE(NUM2UINT(timestamp)); /* "A 5-byte field consisting of a random value generated once per process. * This random value is unique to the machine and process. * * "Drivers MUST NOT have an accessor method on an ObjectID class for * obtaining this value." */ random_component = pvt_get_object_id_random_value(); /* shift left 8 bits, so that the first three bytes of the result are * the meaningful ones */ counter_component = BSON_UINT32_TO_BE(rb_bson_object_id_counter << 8); memcpy(&bytes, &time_component, 4); memcpy(&bytes[4], random_component, 5); memcpy(&bytes[9], &counter_component, 3); rb_bson_object_id_counter = (rb_bson_object_id_counter + 1) % 0x1000000; return rb_str_new(bytes, 12); } /** * Reset the counter. This is purely as an aid for testing. * * @param [ Integer ] i the value to set the counter to (default is 0) */ VALUE rb_bson_object_id_generator_reset_counter(int argc, VALUE* args, VALUE self) { switch(argc) { case 0: rb_bson_object_id_counter = 0; break; case 1: rb_bson_object_id_counter = FIX2INT(args[0]); break; default: rb_raise(rb_eArgError, "Expected 0 or 1 arguments, got %d", argc); } return T_NIL; } /** * 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))); } } } /** * Returns the random number associated with this host and process. If the * process ID changes (e.g. via fork), this will detect the change and * generate another random number. */ uint8_t* pvt_get_object_id_random_value() { static pid_t remembered_pid = 0; static uint8_t remembered_value[BSON_OBJECT_ID_RANDOM_VALUE_LENGTH] = {0}; pid_t pid = getpid(); if (remembered_pid != pid) { remembered_pid = pid; pvt_rand_buf(remembered_value, BSON_OBJECT_ID_RANDOM_VALUE_LENGTH, pid); } return remembered_value; } /** * Attempts to load the SecureRandom module */ VALUE pvt_load_secure_random(VALUE _arg) { rb_require("securerandom"); pvt_SecureRandom = rb_const_get(rb_cObject, rb_intern("SecureRandom")); pvt_has_random_number = rb_respond_to(pvt_SecureRandom, rb_intern("random_number")); // mark SecureRandom so it does not get moved rb_global_variable(&pvt_SecureRandom); return Qnil; } /** * The fallback, if loading `securerandom` fails. */ VALUE pvt_rescue_load_secure_random(VALUE _arg, VALUE _exception) { pvt_SecureRandom = Qnil; return Qnil; } /** * Initializes the RNG. */ void pvt_init_rand() { // SecureRandom may fail to load because it's not present (LoadError), or // because it can't find a random device (NotImplementedError). rb_rescue2(pvt_load_secure_random, Qnil, pvt_rescue_load_secure_random, Qnil, rb_eLoadError, rb_eNotImpError, 0); } /** * Fills the buffer with random bytes. It prefers to use SecureRandom for * this, but in the very unlikely event that SecureRandom is not available, * it will fall back to a much-less-ideal generator using srand/rand. * * The `pid` argument is only used by the fallback, if SecureRandom is not * available. */ void pvt_rand_buf(uint8_t* bytes, int len, int pid) { if (pvt_SecureRandom != Qnil) { VALUE rb_bytes = rb_funcall(pvt_SecureRandom, rb_intern("bytes"), 1, INT2NUM(len)); memcpy(bytes, StringValuePtr(rb_bytes), len); } else { time_t t; uint32_t seed; int ofs = 0; t = time(NULL); seed = ((uint32_t)t << 16) + ((uint32_t)pid % 0xFFFF); srand(seed); while (ofs < len) { int n = rand(); unsigned remaining = len - ofs; if (remaining > sizeof(n)) remaining = sizeof(n); memcpy(bytes+ofs, &n, remaining); ofs += remaining; } } } /** * Returns a random integer between 0 and INT_MAX. */ int pvt_rand() { if (pvt_has_random_number) { VALUE result = rb_funcall(pvt_SecureRandom, rb_intern("random_number"), 1, INT2NUM(INT_MAX)); return NUM2INT(result); } else if (pvt_SecureRandom != Qnil) { int result; VALUE rb_result = rb_funcall(pvt_SecureRandom, rb_intern("bytes"), 1, INT2NUM(sizeof(result))); memcpy(&result, StringValuePtr(rb_result), sizeof(result)); return result; } else { srand((unsigned)time(NULL)); return rand(); } } bson-ruby-5.2.0/ext/bson/write.c000066400000000000000000000552211507420264200165040ustar00rootroot00000000000000/* * 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; } 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); 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); 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){ 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); 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); break; default:{ rb_funcall(val, rb_intern("to_bson"), 1, rb_buffer); 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){ char *c_str = RSTRING_PTR(string); size_t length = RSTRING_LEN(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; 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); break; case T_SYMBOL: key_str = rb_sym_to_s(key); RB_GC_GUARD(key_str); pvt_put_bson_key(b, key_str); break; default: rb_bson_byte_buffer_put_cstring(buffer, rb_funcall(key, rb_intern("to_bson_key"), 0)); } pvt_put_field(b, buffer, val); return ST_CONTINUE; } /* The docstring is in init.c. */ VALUE rb_bson_byte_buffer_put_hash(VALUE self, VALUE hash){ 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.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); } // strlen is a potential vector for out-of-bounds errors, but // the only way for that to happen here, specifically, is if `index` // is greater than 10e16 - 1, which is far beyond the domain of an // int32. 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){ 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); } 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-5.2.0/lib/000077500000000000000000000000001507420264200142065ustar00rootroot00000000000000bson-ruby-5.2.0/lib/bson.rb000066400000000000000000000056121507420264200155000ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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::Error::InvalidObjectId ] 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/vector" 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_ruby.NativeService") else require "bson_native" end rescue LoadError => e $stderr.puts("Failed to load the necessary extensions: #{e.class}: #{e}") raise end bson-ruby-5.2.0/lib/bson/000077500000000000000000000000001507420264200151475ustar00rootroot00000000000000bson-ruby-5.2.0/lib/bson/active_support.rb000066400000000000000000000013161507420264200205440ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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-5.2.0/lib/bson/array.rb000066400000000000000000000140421507420264200166130ustar00rootroot00000000000000# 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. # The top-level BSON module. 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) if buffer.respond_to?(:put_array) buffer.put_array(self) 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) 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::Error::InvalidObjectId ] 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(&: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/extended-json.md). # # 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 # Class-level methods to be added to the Array class. module ClassMethods # Deserialize the array from BSON. # # @note If the argument cannot be parsed, an exception will be raised # and the argument will be left in an undefined state. The caller # must explicitly call `rewind` on the buffer before trying to parse # it again. # # @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 def from_bson(buffer, **options) if buffer.respond_to?(:get_array) buffer.get_array(**options) else parse_array_from_buffer(buffer, **options) end end private # Parse an array from the buffer. # # @param [ ByteBuf ] buffer the buffer to read from # @param [ Hash ] options the optional keyword arguments # # @return [ Array ] the array that was parsed # # @raise [ BSON::Error::BSONDecodeError ] if the expected number of # bytes were not read from the buffer def parse_array_from_buffer(buffer, **options) new.tap do |array| start_position = buffer.read_position expected_byte_size = buffer.get_int32 parse_array_elements_from_buffer(array, buffer, **options) 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 end end # Parse a sequence of array elements from the buffer. # # @param [ Array ] array the array to populate # @param [ ByteBuf ] buffer the buffer to read from # @param [ Hash ] options the optional keyword arguments def parse_array_elements_from_buffer(array, buffer, **options) 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 end end # Register this type when the module is loaded. Registry.register(BSON_TYPE, ::Array) end # Enrich the core Array class with this module. ::Array.include Array ::Array.extend Array::ClassMethods end bson-ruby-5.2.0/lib/bson/big_decimal.rb000066400000000000000000000046241507420264200177210ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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) BSON::Decimal128.new(to_s).to_bson(buffer) 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. If the :mode option # is set to BSON, this will return a BSON::Decimal128 # # @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 | BSON::Decimal128 ] The decimal object. def from_bson(buffer, **options) dec128 = Decimal128.from_bson(buffer, **options) if options[:mode] == :bson dec128 else dec128.to_d end end end # Register this type when the module is loaded. Registry.register(BSON_TYPE, ::BigDecimal) end # Enrich the core BigDecimal class with this module. ::BigDecimal.send(:include, BigDecimal) ::BigDecimal.send(:extend, BigDecimal::ClassMethods) end bson-ruby-5.2.0/lib/bson/binary.rb000066400000000000000000000542571507420264200167750ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 include Comparable # 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, sensitive: 8.chr, vector: 9.chr, user: 128.chr, }.freeze # The starting point of the user-defined subtype range. USER_SUBTYPE = 0x80 # The mappings of single byte subtypes to their symbol counterparts. # # @since 2.0.0 TYPES = SUBTYPES.invert.freeze # Types of vector data. VECTOR_DATA_TYPES = { int8: '0x03'.hex, float32: '0x27'.hex, packed_bit: '0x10'.hex }.freeze # @api private VECTOR_DATA_TYPES_INVERSE = VECTOR_DATA_TYPES.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. attr_reader :type # @return [ String ] The raw type value, as an encoded integer. attr_reader :raw_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? == # Compare this binary object to another object. The two objects must have # the same type for any meaningful comparison. # # @param [ Object ] other The object to compare against. # # @return [ Integer | nil ] If the objects have the same type, the result # is -1 if self < other, 0 if self == other, and 1 if self > other. If # other is not a Binary, or is a Binary of a different type, returns nil. def <=>(other) return nil unless other.is_a?(Binary) && type == other.type data <=> other.data end # Generates a Fixnum hash value for this object. # # Allows using Binary as hash keys. # # @return [ Fixnum ] # # @since 2.3.1 def hash [data, type].hash end # Return a representation of the object for use in # application-level JSON serialization. Since BSON::Binary # is used exclusively in BSON-related contexts, this # method returns the canonical Extended JSON representation. # # @return [ Hash ] The extended json representation. 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/extended-json.md). # # @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 = @raw_type.each_byte.map { |c| c.to_s(16) }.join subtype = "0#{subtype}" if subtype.length == 1 value = Base64.encode64(data).strip if options[:mode] == :legacy { '$binary' => value, '$type' => subtype } else { '$binary' => { 'base64' => value, 'subType' => subtype } } end end # Decode the binary data as a vector data type. # # @return [ BSON::Vector ] The decoded vector data. def as_vector raise BSON::Error, "Cannot decode subtype #{type} as vector" unless type == :vector dtype_value, padding, = data[0..1].unpack('CC') dtype = VECTOR_DATA_TYPES_INVERSE[dtype_value] raise ArgumentError, "Unsupported vector type: #{dtype_value}" unless dtype format = case dtype when :int8 then 'c*' when :float32 then 'f*' when :packed_bit then 'C*' else raise ArgumentError, "Unsupported type: #{dtype}" end BSON::Vector.new(data[2..-1].unpack(format), dtype, padding) 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) initialize_instance(data, type) end # For legacy deserialization support where BSON::Binary objects are # expected to have a specific internal representation (with only # @type and @data instance variables). # # @api private def init_with(coder) initialize_instance(coder['data'], coder['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.inspect}" end case type when :uuid from_uuid_to_uuid(representation || :standard) when :uuid_old from_uuid_old_to_uuid(representation) 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) position = buffer.length buffer.put_int32(0) buffer.put_byte(@raw_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 if type_byte.bytes.first < USER_SUBTYPE type = TYPES[type_byte] if type.nil? raise Error::UnsupportedBinarySubtype, "BSON data contains unsupported binary subtype #{'0x%02x' % type_byte.ord}" end else type = type_byte 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) raise ArgumentError, "Representation must be given as a symbol: #{representation}" if representation.is_a?(String) uuid_binary = uuid.delete('-').scan(/../).map(&:hex).map(&:chr).join representation ||= :standard handler = :"from_#{representation}_uuid" raise ArgumentError, "Invalid representation: #{representation}" unless respond_to?(handler) send(handler, uuid_binary) end # Constructs a new binary object from a standard-format binary UUID # representation. # # @param [ String ] uuid_binary the UUID data # # @return [ BSON::Binary ] the Binary object # # @api private def self.from_standard_uuid(uuid_binary) new(uuid_binary, :uuid) end # Constructs a new binary object from a csharp legacy-format binary UUID # representation. # # @param [ String ] uuid_binary the UUID data # # @return [ BSON::Binary ] the Binary object # # @api private def self.from_csharp_legacy_uuid(uuid_binary) uuid_binary.sub!(/\A(.)(.)(.)(.)(.)(.)(.)(.)(.{8})\z/, '\4\3\2\1\6\5\8\7\9') new(uuid_binary, :uuid_old) end # Constructs a new binary object from a java legacy-format binary UUID # representation. # # @param [ String ] uuid_binary the UUID data # # @return [ BSON::Binary ] the Binary object # # @api private def self.from_java_legacy_uuid(uuid_binary) uuid_binary.sub!(/\A(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)\z/) do (::Regexp.last_match[1..8].reverse + ::Regexp.last_match[9..16].reverse).join end new(uuid_binary, :uuid_old) end # Constructs a new binary object from a python legacy-format binary UUID # representation. # # @param [ String ] uuid_binary the UUID data # # @return [ BSON::Binary ] the Binary object # # @api private def self.from_python_legacy_uuid(uuid_binary) new(uuid_binary, :uuid_old) end # Constructs a new binary object from a binary vector. # @param [ BSON::Vector | Array ] vector The vector data. # @param [ Symbol | nil ] dtype The vector data type, must be nil if vector is a BSON::Vector. # @param [ Integer ] padding The number of bits in the final byte that are to # be ignored when a vector element's size is less than a byte. Must be 0 if vector is a BSON::Vector. # @param [ Boolean ] validate_vector_data Whether to validate the vector data. # # @return [ BSON::Binary ] The binary object. def self.from_vector(vector, dtype = nil, padding = 0, validate_vector_data: false) data, dtype, padding = extract_args_for_vector(vector, dtype, padding) validate_args_for_vector!(data, dtype, padding) format = case dtype when :int8 then 'c*' when :float32 then 'f*' when :packed_bit then 'C*' else raise ArgumentError, "Unsupported type: #{dtype}" end if validate_vector_data validate_vector_data!(data, dtype) end metadata = [ VECTOR_DATA_TYPES[dtype], padding ].pack('CC') data = data.pack(format) new(metadata.concat(data), :vector) end private # Extracts the arguments for a binary vector. # # @param [ BSON::Vector | Array ] vector The vector data. # @param [ ::Symbol | nil ] dtype The vector data type, must be nil if vector is a BSON::Vector. # @param [ Integer ] padding The padding. Must be 0 if vector is a BSON::Vector. # # @return [ Array ] The extracted data, dtype, and padding. def self.extract_args_for_vector(vector, dtype, padding) if vector.is_a?(BSON::Vector) if dtype || padding != 0 raise ArgumentError, 'Do not specify dtype and padding if the first argument is BSON::Vector' end data = vector.data dtype = vector.dtype padding = vector.padding else data = vector end [ data, dtype, padding ] end private_class_method :extract_args_for_vector # Validate the arguments for a binary vector. # @param [ Array ] data The vector data. # @param [ ::Symbol ] dtype The vector data type. # @param [ Integer ] padding The padding. Must be 0 if vector is a BSON::Vector. # @raise [ ArgumentError ] If the arguments are invalid. def self.validate_args_for_vector!(data, dtype, padding) raise ArgumentError, "Unknown dtype #{dtype}" unless VECTOR_DATA_TYPES.key?(dtype) if %i[int8 float32].include?(dtype) raise ArgumentError, 'Padding applies only to packed_bit' if padding != 0 elsif padding.positive? && data.empty? raise ArgumentError, 'Padding must be zero when the vector is empty for PACKED_BIT' elsif padding.negative? || padding > 7 raise ArgumentError, "Padding must be between 0 and 7, got #{padding}" end end private_class_method :validate_args_for_vector! # Validate that all the values in the vector data are valid for the given dtype. # # @param [ Array ] data The vector data. # @param [ ::Symbol ] dtype The vector data type. def self.validate_vector_data!(data, dtype) validator = case dtype when :int8 ->(v) { v.is_a?(Integer) && v.between?(-128, 127) } when :float32 ->(v) { v.is_a?(Float) } when :packed_bit ->(v) { v.is_a?(Integer) && v.between?(0, 255) } else raise ArgumentError, "Unsupported type: #{dtype}" end data.each do |v| raise ArgumentError, "Invalid value #{v} for type #{dtype}" unless validator.call(v) end end private_class_method :validate_vector_data! # initializes an instance of BSON::Binary. # # @param [ String ] data the data to initialize the object with # @param [ Symbol ] type the type to assign the binary object def initialize_instance(data, type) @type = 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. data = data.dup.force_encoding('BINARY') unless data.encoding == Encoding.find('BINARY') @data = data end # Converts the Binary UUID object to a UUID of the given representation. # Currently, only :standard representation is supported. # # @param [ Symbol ] representation The representation to target (must be # :standard) # # @return [ String ] the UUID as a string def from_uuid_to_uuid(representation) if representation != :standard raise ArgumentError, 'Binary of type :uuid can only be stringified to :standard representation, ' \ "requested: #{representation.inspect}" end data .chars .map { |n| '%02x' % n.ord } .join .sub(/\A(.{8})(.{4})(.{4})(.{4})(.{12})\z/, '\1-\2-\3-\4-\5') end # Converts the UUID-old object to a UUID of the given representation. # # @param [ Symbol ] representation The representation to target # # @return [ String ] the UUID as a string def from_uuid_old_to_uuid(representation) if representation.nil? raise ArgumentError, 'Representation must be specified for BSON::Binary objects of type :uuid_old' end hex = data.chars.map { |n| '%02x' % n.ord }.join handler = :"from_uuid_old_to_#{representation}_uuid" raise ArgumentError, "Invalid representation: #{representation}" unless respond_to?(handler, true) send(handler, hex) .sub(/\A(.{8})(.{4})(.{4})(.{4})(.{12})\z/, '\1-\2-\3-\4-\5') end # Tries to convert a UUID-old object to a standard representation, which is # not supported. # # @param [ String ] hex The hexadecimal string to convert # # @raise [ ArgumentError ] because standard representation is not supported def from_uuid_old_to_standard_uuid(_hex) raise ArgumentError, 'BSON::Binary objects of type :uuid_old cannot be stringified to :standard representation' end # Converts a UUID-old object to a csharp-legacy representation. # # @param [ String ] hex The hexadecimal string to convert # # @return [ String ] the csharp-legacy-formatted UUID def from_uuid_old_to_csharp_legacy_uuid(hex) hex.sub(/\A(..)(..)(..)(..)(..)(..)(..)(..)(.{16})\z/, '\4\3\2\1\6\5\8\7\9') end # Converts a UUID-old object to a java-legacy representation. # # @param [ String ] hex The hexadecimal string to convert # # @return [ String ] the java-legacy-formatted UUID def from_uuid_old_to_java_legacy_uuid(hex) hex.sub(/\A(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)\z/) do (::Regexp.last_match[1..8].reverse + ::Regexp.last_match[9..16].reverse).join end end # Converts a UUID-old object to a python-legacy representation. # # @param [ String ] hex The hexadecimal string to convert # # @return [ String ] the python-legacy-formatted UUID def from_uuid_old_to_python_legacy_uuid(hex) hex end # Validate the provided type is a valid type. # # @api private # # @example Validate the type. # binary.validate_type!(:user) # # @param [ Symbol | String | Integer ] type The provided type. # # @return [ Symbol ] the symbolic type corresponding to the argument. # # @raise [ BSON::Error::InvalidBinaryType ] The the type is invalid. # # @since 2.0.0 def validate_type!(type) case type when Integer then validate_integer_type!(type) when String if type.length > 1 validate_symbol_type!(type.to_sym) else validate_integer_type!(type.bytes.first) end when Symbol then validate_symbol_type!(type) else raise BSON::Error::InvalidBinaryType, type end end # Test that the given integer type is valid. # # @param [ Integer ] type the provided type # # @return [ Symbol ] the symbolic type corresponding to the argument. # # @raise [ BSON::Error::InvalidBinaryType] if the type is invalid. def validate_integer_type!(type) @raw_type = type.chr.force_encoding('BINARY').freeze if type < USER_SUBTYPE raise BSON::Error::InvalidBinaryType, type unless TYPES.key?(@raw_type) return TYPES[@raw_type] end :user end # Test that the given symbol type is valid. # # @param [ Symbol ] type the provided type # # @return [ Symbol ] the symbolic type corresponding to the argument. # # @raise [ BSON::Error::InvalidBinaryType] if the type is invalid. def validate_symbol_type!(type) raise BSON::Error::InvalidBinaryType, type unless SUBTYPES.key?(type) @raw_type = SUBTYPES[type] type end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, self) end end bson-ruby-5.2.0/lib/bson/boolean.rb000066400000000000000000000032121507420264200171110ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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-5.2.0/lib/bson/code.rb000066400000000000000000000065661507420264200164230ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 # Return a representation of the object for use in # application-level JSON serialization. Since BSON::Code # is used exclusively in BSON-related contexts, this # method returns the canonical Extended JSON representation. # # @return [ Hash ] The extended json representation. 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/extended-json.md). # # @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) 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-5.2.0/lib/bson/code_with_scope.rb000066400000000000000000000107741507420264200206430ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 # Return a representation of the object for use in # application-level JSON serialization. Since BSON::CodeWithScope # is used exclusively in BSON-related contexts, this # method returns the canonical Extended JSON representation. # # @return [ Hash ] The extended json representation. 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/extended-json.md). # # @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) 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-5.2.0/lib/bson/config.rb000066400000000000000000000013771507420264200167510ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 end end bson-ruby-5.2.0/lib/bson/date.rb000066400000000000000000000033441507420264200164150ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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) 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-5.2.0/lib/bson/date_time.rb000066400000000000000000000025361507420264200174350ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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) 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-5.2.0/lib/bson/db_pointer.rb000066400000000000000000000065071507420264200176310ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 # Return a representation of the object for use in # application-level JSON serialization. Since BSON::DbPointer # is used exclusively in BSON-related contexts, this # method returns the canonical Extended JSON representation. # # @return [ Hash ] The extended json representation. 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/extended-json.md). # # @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) buffer.put_string(ref) id.to_bson(buffer) 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-5.2.0/lib/bson/dbref.rb000066400000000000000000000106741507420264200165660ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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. # # @raise [ BSON::Error::InvalidDBRefArgument ] if giving invalid arguments # to the constructor. 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 Error::InvalidDBRefArgument, '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 Error::InvalidDBRefArgument, '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 Error::InvalidDBRefArgument, "DBRef must have #{key}: #{hash}" end end unless hash['$ref'].is_a?(String) raise Error::InvalidDBRefArgument, "The value for key $ref must be a string, got: #{hash['$ref']}" end if db = hash['$db'] unless db.is_a?(String) raise Error::InvalidDBRefArgument, "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. # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. def to_bson(buffer = ByteBuffer.new) as_json.to_bson(buffer) 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-5.2.0/lib/bson/decimal128.rb000066400000000000000000000166461507420264200173420ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 # Return a string representation of the Decimal128 use in standard # application-level JSON serialization. Returns nil for non-real # numbers such as NaN and Infinity to be compatible with ActiveSupport. # This method is intentionally different from #as_extended_json. # # @example Get the Decimal128 as a JSON-serializable object. # decimal.as_json # # @return [ String | nil ] The decimal128 as a String or nil for non-representable numbers. def as_json(*args) value = to_s value unless %w[NaN Infinity -Infinity].include?(value) end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md). # # @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_d <=> case other when Decimal128 other.to_d 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 [ BSON::Error::InvalidDecimal128Argument ] 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 Error::InvalidDecimal128Argument.new end end # Get the BSON type for Decimal128. def bson_type BSON_TYPE 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) 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_d # => # # 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. def to_d @big_decimal ||= BigDecimal(to_s) end alias :to_big_decimal :to_d 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::Error:InvalidDecimal128String ] 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 end end bson-ruby-5.2.0/lib/bson/decimal128/000077500000000000000000000000001507420264200170005ustar00rootroot00000000000000bson-ruby-5.2.0/lib/bson/decimal128/builder.rb000066400000000000000000000327701507420264200207640ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 Error::InvalidDecimal128Range.new end unless valid_significand?(significand) raise Error::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 = /\A[\-\+]?(\d+(\.\d*)?|\.\d+)(E[\-\+]?\d+)?\Z/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 _, sign, digits_str = SIGN_AND_DIGITS_REGEX.match(@string).to_a digits, _, scientific_exp = digits_str.partition(SCIENTIFIC_EXPONENT_REGEX) before_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 Error::InvalidDecimal128String.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, _, 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 end bson-ruby-5.2.0/lib/bson/document.rb000066400000000000000000000271571507420264200173260ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 def deep_symbolize_keys! warn <<~WARN [DEPRECATION] `deep_symbolize_keys!` is not supported on BSON::Document instances. Please convert the document to a Hash first (using `#to_h`), then call `#deep_symbolize_keys!` on the Hash. This will raise an error starting with the v6.0.0 release. WARN 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-5.2.0/lib/bson/environment.rb000066400000000000000000000026171507420264200200460ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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-5.2.0/lib/bson/error.rb000066400000000000000000000013631507420264200166300ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON # Base exception class for all BSON-related errors. class Error < StandardError end end require 'bson/error/bson_decode_error' require 'bson/error/ext_json_parse_error' require 'bson/error/invalid_binary_type' require 'bson/error/invalid_dbref_argument' require 'bson/error/invalid_decimal128_argument' require 'bson/error/invalid_decimal128_range' require 'bson/error/invalid_decimal128_string' require 'bson/error/invalid_key' require 'bson/error/invalid_object_id' require 'bson/error/invalid_regexp_pattern' require 'bson/error/unrepresentable_precision' require 'bson/error/unserializable_class' require 'bson/error/unsupported_binary_subtype' require 'bson/error/unsupported_type' bson-ruby-5.2.0/lib/bson/error/000077500000000000000000000000001507420264200163005ustar00rootroot00000000000000bson-ruby-5.2.0/lib/bson/error/bson_decode_error.rb000066400000000000000000000002621507420264200223020ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # Exception raised when BSON decoding fails. class BSONDecodeError < Error end end end bson-ruby-5.2.0/lib/bson/error/ext_json_parse_error.rb000066400000000000000000000002741507420264200230640ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # Exception raised when Extended JSON parsing fails. class ExtJSONParseError < Error end end end bson-ruby-5.2.0/lib/bson/error/illegal_key.rb000066400000000000000000000010561507420264200211100ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # Raised when validating keys and a key is illegal in MongoDB class IllegalKey < Error # Instantiate the exception. # # @example Instantiate the exception. # BSON::Error::IllegalKey.new(string) # # @param [ String ] string The illegal string. # # @api private def initialize(string) super("'#{string}' is an illegal key in MongoDB. Keys may not start with '$' or contain a '.'.") end end end end bson-ruby-5.2.0/lib/bson/error/invalid_binary_type.rb000066400000000000000000000015561507420264200226670ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # Raised when providing an invalid type to the Binary. class InvalidBinaryType < Error # @return [ Object ] The invalid type. attr_reader :type # Instantiate the new error. # # @example Instantiate the error. # InvalidBinaryType.new(:error) # # @param [ Object ] type The invalid type. # # @api private 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. def message "#{type.inspect} is not a valid binary type. " + "Please use one of #{BSON::Binary::SUBTYPES.keys.map(&:inspect).join(", ")}." end end end end bson-ruby-5.2.0/lib/bson/error/invalid_dbref_argument.rb000066400000000000000000000003451507420264200233210ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # Raised when trying to create a BSON::DBRef from an object that is an invalid DBRef. class InvalidDBRefArgument < Error end end end bson-ruby-5.2.0/lib/bson/error/invalid_decimal128_argument.rb000066400000000000000000000011251507420264200240650ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # Raised when trying to create a Decimal128 from an object that is neither a String nor a BigDecimal. class InvalidDecimal128Argument < Error # The custom error message for this error. 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. def message MESSAGE end end end end bson-ruby-5.2.0/lib/bson/error/invalid_decimal128_range.rb000066400000000000000000000010631507420264200233400ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # Raised when the exponent is outside the valid range. class InvalidDecimal128Range < Error # The custom error message for this error. # # @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. def message MESSAGE end end end end bson-ruby-5.2.0/lib/bson/error/invalid_decimal128_string.rb000066400000000000000000000011011507420264200235430ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # Raised when trying to create a Decimal128 from a string with # an invalid format. class InvalidDecimal128String < Error # The custom error message for this error. 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. def message MESSAGE end end end end bson-ruby-5.2.0/lib/bson/error/invalid_key.rb000066400000000000000000000010531507420264200211220ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # Raised when trying to serialize an object into a key. class InvalidKey < Error # Instantiate the exception. # # @example Instantiate the exception. # BSON::Object::InvalidKey.new(object) # # @param [ Object ] object The object that was meant for the key. # # @api private def initialize(object) super("#{object.class} instances are not allowed as keys in a BSON document.") end end end end bson-ruby-5.2.0/lib/bson/error/invalid_object_id.rb000066400000000000000000000003021507420264200222500ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # Raised when trying to create an object id with invalid data. class InvalidObjectId < Error; end end end bson-ruby-5.2.0/lib/bson/error/invalid_regexp_pattern.rb000066400000000000000000000004571507420264200233700ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # 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-5.2.0/lib/bson/error/unrepresentable_precision.rb000066400000000000000000000006531507420264200241020ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # Raised when the significand provided is outside the valid range. class UnrepresentablePrecision < Error # 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 end end bson-ruby-5.2.0/lib/bson/error/unserializable_class.rb000066400000000000000000000004631507420264200230260ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # 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 end end bson-ruby-5.2.0/lib/bson/error/unsupported_binary_subtype.rb000066400000000000000000000003571507420264200243410ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # Exception raised when decoding BSON and the data contains an # unsupported binary subtype. class UnsupportedBinarySubtype < Error end end end bson-ruby-5.2.0/lib/bson/error/unsupported_type.rb000066400000000000000000000003141507420264200222540ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all module BSON class Error # Raised when trying to get a type from the registry that doesn't exist. class UnsupportedType < Error; end end end bson-ruby-5.2.0/lib/bson/ext_json.rb000066400000000000000000000350071507420264200173320ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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/extended-json.md 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-5.2.0/lib/bson/false_class.rb000066400000000000000000000033231507420264200177540ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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) 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-5.2.0/lib/bson/float.rb000066400000000000000000000067301507420264200166070ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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) 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/extended-json.md). # # 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-5.2.0/lib/bson/hash.rb000066400000000000000000000165671507420264200164360ustar00rootroot00000000000000# 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. # The top-level BSON module. 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 module Hash # A hash, also called an embedded document, is type 0x03 in the BSON spec. 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 def to_bson(buffer = ByteBuffer.new) # If the native buffer version has an optimized version, we'll call # it directly. Otherwise, we'll serialize the hash the hard way. if buffer.respond_to?(:put_hash) buffer.put_hash(self) else serialize_to_buffer(buffer) 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. 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/extended-json.md). # # 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 private # Serialize this hash instance to the given buffer. # # @param [ ByteBuf ] buffer The buffer to receive the serialized hash. def serialize_to_buffer(buffer) position = buffer.length buffer.put_int32(0) serialize_key_value_pairs(buffer) buffer.put_byte(NULL_BYTE) buffer.replace_int32(position, buffer.length - position) end # Serialize the key/value pairs in this hash instance to the given # buffer. # # @param [ ByteBuf ] buffer The buffer to received the serialized # key/value pairs. # # @raise [ Error::UnserializableClass ] if a value cannot be serialized def serialize_key_value_pairs(buffer) 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 serialize_key(buffer, key) value.to_bson(buffer) end end # Serialize the key/value pairs in this hash instance to the given # buffer. # # @param [ ByteBuf ] buffer The buffer to received the serialized # key/value pairs. # # @raise [ ArgumentError ] if the string cannot be serialized # @raise [ EncodingError ] if the string is not a valid encoding def serialize_key(buffer, key) 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 # The methods to augment the Hash class with (class-level methods). module ClassMethods # Deserialize the hash from BSON. # # @note If the argument cannot be parsed, an exception will be raised # and the argument will be left in an undefined state. The caller # must explicitly call `rewind` on the buffer before trying to parse # it again. # # @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 def from_bson(buffer, **options) if buffer.respond_to?(:get_hash) buffer.get_hash(**options) else hash = parse_hash_from_buffer(buffer, **options) maybe_dbref(hash) end end private # If the hash looks like a DBRef, try and decode it as such. If # is turns out to be invalid--or if it doesn't look like a DBRef # to begin with--return the hash itself. # # @param [ Hash ] hash the hash to try and decode # # @return [ DBRef | Hash ] the result of decoding the hash def maybe_dbref(hash) return DBRef.new(hash) if hash['$ref'] && hash['$id'] hash rescue Error::InvalidDBRefArgument hash end # Given a byte buffer, extract and return a hash from it. # # @param [ ByteBuf ] buffer the buffer to read data from # @param [ Hash ] options the keyword arguments # # @return [ Hash ] the hash parsed from the buffer def parse_hash_from_buffer(buffer, **options) hash = Document.allocate start_position = buffer.read_position expected_byte_size = buffer.get_int32 parse_hash_contents(hash, buffer, **options) actual_byte_size = buffer.read_position - start_position return hash unless 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 # Given an empty hash and a byte buffer, parse the key/value pairs from # the buffer and populate the hash with them. # # @param [ Hash ] hash the hash to populate # @param [ ByteBuf ] buffer the buffer to read data from # @param [ Hash ] options the keyword arguments def parse_hash_contents(hash, buffer, **options) 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 end end # Register this type when the module is loaded. Registry.register(BSON_TYPE, ::Hash) end # Enrich the core Hash class with this module. ::Hash.include Hash ::Hash.extend Hash::ClassMethods end bson-ruby-5.2.0/lib/bson/int32.rb000066400000000000000000000101001507420264200164230ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 include JSON # 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) 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 # # @return [ String ] The string key. # # @since 4.2.0 def to_bson_key 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 :=== :== # Return a string representation of the Int32 for use in # application-level JSON serialization. This method is intentionally # different from #as_extended_json. # # @example Get the Int32 as a JSON-serializable object. # int32.as_json # # @return [ Integer ] The Int32 as an Integer. def as_json(**options) value end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md). # # 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-5.2.0/lib/bson/int64.rb000066400000000000000000000101341507420264200164370ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 include JSON # 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) 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 # # @return [ String ] The string key. # # @since 4.2.0 def to_bson_key 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 :=== :== # Return a string representation of the Int64 for use in # application-level JSON serialization. This method is intentionally # different from #as_extended_json. # # @example Get the Int64 as a JSON-serializable object. # int64.as_json # # @return [ Integer ] The Int64 as an Integer. def as_json(**options) value end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md). # # 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-5.2.0/lib/bson/integer.rb000066400000000000000000000136741507420264200171440ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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) 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 # # @return [ String ] The string key. # # @since 2.0.0 def to_bson_key self end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md). # # 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-5.2.0/lib/bson/json.rb000066400000000000000000000021611507420264200164450ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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-5.2.0/lib/bson/max_key.rb000066400000000000000000000045521507420264200171370ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 # Return a representation of the object for use in # application-level JSON serialization. Since BSON::MaxKey # is used exclusively in BSON-related contexts, this # method returns the canonical Extended JSON representation. # # @return [ Hash ] The extended json representation. 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/extended-json.md). # # @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-5.2.0/lib/bson/min_key.rb000066400000000000000000000045501507420264200171330ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 # Return a representation of the object for use in # application-level JSON serialization. Since BSON::MinKey # is used exclusively in BSON-related contexts, this # method returns the canonical Extended JSON representation. # # @return [ Hash ] The extended json representation. 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/extended-json.md). # # @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-5.2.0/lib/bson/nil_class.rb000066400000000000000000000032641507420264200174500ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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-5.2.0/lib/bson/object.rb000066400000000000000000000053711507420264200167500ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 [ BSON::Error::InvalidKey ] Always raises an exception. # # @see http://bsonspec.org/#/specification # # @since 2.2.4 def to_bson_key raise Error::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/extended-json.md). # # 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/extended-json.md). # # Subclasses should override this method to provide custom serialization # to Extended JSON. # # @return [ Object ] The extended json representation. def as_extended_json(**_options) self end end # Enrich the core Object class with this module. # # @since 2.2.4 ::Object.send(:include, Object) end bson-ruby-5.2.0/lib/bson/object_id.rb000066400000000000000000000252571507420264200174310ustar00rootroot00000000000000# 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 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 a string representation of the object id for use in # application-level JSON serialization. This method is intentionally # different from #as_extended_json. # # @example Get the object id as a JSON-serializable object. # object_id.as_json # # @return [ String ] The object id as a string. def as_json(*_) to_s end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md). # # @return [ Hash ] The extended json representation. def as_extended_json(**_) { '$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('#{self}')" 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) 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 # Extract the process-specific part of the object id. This is used only # internally, for testing, and should not be used elsewhere. # # @return [ String ] The process portion of the id. # # @api private def _process_part to_s[8, 10] end # Extract the counter-specific part of the object id. This is used only # internally, for testing, and should not be used elsewhere. # # @return [ String ] The counter portion of the id. # # @api private def _counter_part to_s[18, 6] end # Extended by native code (see init.c, util.c, GeneratorExtension.java) # # @api private # # rubocop:disable Lint/EmptyClass class Generator end # rubocop:enable Lint/EmptyClass # We keep one global generator for object ids. @@generator = Generator.new # Accessor for querying the generator directly; used in testing. # # @api private def self._generator @@generator end private def initialize_copy(other) generate_data other.instance_variable_set(:@raw_data, @raw_data) end def generate_data repair if defined?(@data) # rubocop:disable Naming/MemoizedInstanceVariableName @raw_data ||= @@generator.next_object_id # rubocop:enable Naming/MemoizedInstanceVariableName 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. # @param [ Hash ] _ An optional hash of keyword arguments (unused). # # @return [ BSON::ObjectId ] The object id. # # @since 2.0.0 def from_bson(buffer, **_) 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::Error::InvalidObjectId ] If the provided string is invalid. # # @return [ BSON::ObjectId ] The new object id. # # @since 2.0.0 def from_string(string) raise Error::InvalidObjectId, "'#{string}' is an invalid ObjectId." unless legal?(string) 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 [ BSON::Error::InvalidObjectId ] If the array is not 12 elements. # # @return [ String ] The result of the block. # # @since 2.0.0 def repair(object) raise Error::InvalidObjectId, "#{object.inspect} is not a valid object id." if object.size != 12 block_given? ? yield(object) : object end # The largest numeric value that can be converted to an integer by MRI's # NUM2UINT. Further, the spec dictates that the time component of an # ObjectID must be no more than 4 bytes long, so the spec itself is # constrained in this regard. MAX_INTEGER = 2**32 # Returns an integer timestamp (seconds since the Epoch). Primarily used # by the generator to produce object ids. # # @note This value is guaranteed to be no more than 4 bytes in length. A # time value far enough in the future to require a larger integer than # 4 bytes will be truncated to 4 bytes. # # @return [ Integer ] the number of seconds since the Epoch. def timestamp ::Time.now.to_i % MAX_INTEGER end end # Register this type when the module is loaded. # # @since 2.0.0 Registry.register(BSON_TYPE, self) end end bson-ruby-5.2.0/lib/bson/open_struct.rb000066400000000000000000000031771507420264200200510ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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) if Environment.ruby_1_9? marshal_dump.dup else to_h end.to_bson(buffer) 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-5.2.0/lib/bson/regexp.rb000066400000000000000000000215001507420264200167640ustar00rootroot00000000000000# 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. # The top-level BSON module. 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. def as_json(*) { '$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. # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification def to_bson(buffer = ByteBuffer.new) 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.nobits?(::Regexp::EXTENDED) ? NO_VALUE : EXTENDED_VALUE end def bson_ignorecase options.nobits?(::Regexp::IGNORECASE) ? NO_VALUE : IGNORECASE_VALUE end def bson_dotall # Ruby Regexp's MULTILINE is equivalent to BSON's dotall value options.nobits?(::Regexp::MULTILINE) ? NO_VALUE : NEWLINE_VALUE end # Represents the raw values for the regular expression. # # @see https://jira.mongodb.org/browse/RUBY-698 class Raw include JSON # @return [ String ] pattern The regex pattern. attr_reader :pattern # @return [ String ] 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. def compile @compile ||= ::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 | Symbol ] options The options. 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 else raise ArgumentError, 'Regexp options must be a String or Symbol' end @pattern = pattern @options = options.to_s end # Allow automatic delegation of methods to the Regexp object # returned by +compile+. # # @param [ String] method The name of a method. def respond_to_missing?(method, include_private = false) # YAML calls #respond_to? during deserialization, before the object # is initialized. defined?(@pattern) && compile.respond_to?(method, include_private) 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. # # @return [ BSON::ByteBuffer ] The buffer with the encoded object. # # @see http://bsonspec.org/#/specification def to_bson(buffer = ByteBuffer.new) 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. def as_json(*) 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/extended-json.md). # # @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. 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 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 # Class-level methods to be added to the Regexp class. module ClassMethods # Deserialize the regular expression from BSON. # # @note If the argument cannot be parsed, an exception will be raised # and the argument will be left in an undefined state. The caller # must explicitly call `rewind` on the buffer before trying to parse # it again. # # @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 def from_bson(buffer, **_) pattern = buffer.get_cstring options = buffer.get_cstring Raw.new(pattern, options) end end # Register this type when the module is loaded. Registry.register(BSON_TYPE, ::Regexp) end # Enrich the core Regexp class with this module. ::Regexp.include Regexp ::Regexp.extend Regexp::ClassMethods end bson-ruby-5.2.0/lib/bson/registry.rb000066400000000000000000000045111507420264200173450ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 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 Error::UnsupportedType.new(message) end end end bson-ruby-5.2.0/lib/bson/specialized.rb000066400000000000000000000040361507420264200177730ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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) 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-5.2.0/lib/bson/string.rb000066400000000000000000000064651507420264200170150ustar00rootroot00000000000000# rubocop:todo all # -*- 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) 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. # # @return [ String ] The encoded string. # # @see http://bsonspec.org/#/specification # # @since 2.0.0 def to_bson_key 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::Error::InvalidObjectId ] 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 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-5.2.0/lib/bson/symbol.rb000066400000000000000000000136141507420264200170060ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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) 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 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/extended-json.md). # # @return [ Hash ] The extended json representation. def as_extended_json(**_options) { "$symbol" => to_s } end class Raw include JSON # 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) buffer.put_string(to_s) end def bson_type Symbol::BSON_TYPE end # Return a string representation of the raw symbol for use in # application-level JSON serialization. This method is intentionally # different from #as_extended_json. # # @example Get the raw symbol as a JSON-serializable object. # raw_symbol.as_json # # @return [ String ] The raw symbol as a String. def as_json(*args) to_s end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md). # # @return [ Hash ] 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-5.2.0/lib/bson/time.rb000066400000000000000000000106261507420264200164370ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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) 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/extended-json.md). # # @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-5.2.0/lib/bson/time_with_zone.rb000066400000000000000000000040231507420264200205170ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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) 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 # @api private 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 end # Enrich the ActiveSupport::TimeWithZone class with this module. # # @since 4.4.0 ActiveSupport::TimeWithZone.send(:include, TimeWithZone) end bson-ruby-5.2.0/lib/bson/timestamp.rb000066400000000000000000000107251507420264200175040ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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/extended-json.md). # # @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) 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-5.2.0/lib/bson/true_class.rb000066400000000000000000000033111507420264200176360ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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) 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-5.2.0/lib/bson/undefined.rb000066400000000000000000000043121507420264200174350ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all # 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 JSON 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 # Return a string representation of the BSON::Undefined for use in # application-level JSON serialization. This method is intentionally # different from #as_extended_json. # # @example Get the undefined as a JSON-serializable object. # undefined.as_json # # @return [ nil ] The undefined as nil. def as_json(*args) nil end # Converts this object to a representation directly serializable to # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md). # # @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-5.2.0/lib/bson/vector.rb000066400000000000000000000030771507420264200170050ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2025-present 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 # Vector of numbers along with metadata for binary interoperability. class Vector < ::Array # @return [ Integer ] The data type stored in the vector. attr_reader :dtype # @return [ Integer ] The number of bits in the final byte that are to # be ignored when a vector element's size is less than a byte # and the length of the vector is not a multiple of 8. attr_reader :padding # @return [ BSON::ByteBuffer ] The data in the vector. def data self end # @param [ ::Array ] data The data to initialize the vector with. # @param [ Integer ] dtype The data type of the vector. # @param [ Integer ] padding The number of bits in the final byte that are to # be ignored when a vector element's size is less than a byte # and the length of the vector is not a multiple of 8. def initialize(data, dtype, padding = 0) @dtype = dtype @padding = padding super(data.dup) end end end bson-ruby-5.2.0/lib/bson/version.rb000066400000000000000000000003771507420264200171700ustar00rootroot00000000000000# frozen_string_literal: true module BSON # The current version of the library. # # NOTE: this file is automatically updated via `rake candidate:create`. # Manual changes to this file may be overwritten by that rake task. VERSION = '5.2.0' end bson-ruby-5.2.0/perf/000077500000000000000000000000001507420264200143745ustar00rootroot00000000000000bson-ruby-5.2.0/perf/README.md000066400000000000000000000030131507420264200156500ustar00rootroot00000000000000Performance 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-5.2.0/perf/Rakefile000066400000000000000000000040771507420264200160510ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/perf/bench.rb000066400000000000000000000153631507420264200160100ustar00rootroot00000000000000# rubocop:todo all # 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" require 'bson' 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-5.2.0/perf/bench_test.rb000066400000000000000000000727231507420264200170520ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/product.yml000066400000000000000000000003531507420264200156440ustar00rootroot00000000000000--- name: BSON for Ruby description: a fully featured [BSON specification](https://bsonspec.org/) implementation in Ruby package: bson jira: https://jira.mongodb.org/projects/RUBY version: number: 5.2.0 file: lib/bson/version.rb bson-ruby-5.2.0/sbom.json000066400000000000000000000030211507420264200152670ustar00rootroot00000000000000{ "metadata": { "timestamp": "2024-06-12T07:06:17.526721+00:00", "tools": [ { "externalReferences": [ { "type": "build-system", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions" }, { "type": "distribution", "url": "https://pypi.org/project/cyclonedx-python-lib/" }, { "type": "documentation", "url": "https://cyclonedx-python-library.readthedocs.io/" }, { "type": "issue-tracker", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues" }, { "type": "license", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE" }, { "type": "release-notes", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md" }, { "type": "vcs", "url": "https://github.com/CycloneDX/cyclonedx-python-lib" }, { "type": "website", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/#readme" } ], "name": "cyclonedx-python-lib", "vendor": "CycloneDX", "version": "6.4.4" } ] }, "serialNumber": "urn:uuid:555775d6-266f-4f33-84a0-e8ab6508d27e", "version": 1, "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json", "bomFormat": "CycloneDX", "specVersion": "1.5" } bson-ruby-5.2.0/spec/000077500000000000000000000000001507420264200143725ustar00rootroot00000000000000bson-ruby-5.2.0/spec/README.md000066400000000000000000000005111507420264200156460ustar00rootroot00000000000000# 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-5.2.0/spec/bson/000077500000000000000000000000001507420264200153335ustar00rootroot00000000000000bson-ruby-5.2.0/spec/bson/array_spec.rb000066400000000000000000000077221507420264200200200ustar00rootroot00000000000000# rubocop:todo all # 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 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::Error::InvalidObjectId) end end end describe '#as_extended_json' do let(:object) do ['one', :two, 3, 4.0, nil] end let(:expected) do ["one", { "$symbol" => "two" }, { "$numberInt" => "3" }, { "$numberDouble"=> "4.0" }, nil] end it 'returns the extended serialization' do expect(object.as_extended_json).to eq(expected) end it_behaves_like 'an Extended JSON serializable object' end end bson-ruby-5.2.0/spec/bson/big_decimal_spec.rb000066400000000000000000000176751507420264200211310ustar00rootroot00000000000000# rubocop:todo all # 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 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_d) 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::Error::InvalidDecimal128Range) 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::Error::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 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 end bson-ruby-5.2.0/spec/bson/binary_spec.rb000066400000000000000000000224211507420264200201570ustar00rootroot00000000000000# rubocop:todo all # 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") } let(:testing3) { described_class.new("testing", :user) } describe "Comparable" do 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 context 'for objects with identical data but different types' do it 'returns false' do expect(testing1).not_to eql(testing3) end end end describe '#<=>' do context 'with a non-Binary object' do it 'returns nil' do expect(testing1 <=> 'bogus').to be_nil end end context 'with identical type and data' do it 'returns 0' do expect(testing1 <=> testing2).to be == 0 end end context 'with mismatched type' do it 'returns nil' do expect(testing1 <=> testing3).to be_nil end end context 'with identical type but mismatched data' do it 'returns -1 when a < b' do expect(not_testing <=> testing1).to be == -1 end it 'returns 1 when a > b' do expect(testing1 <=> not_testing).to be == 1 end 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_extended_json" do let(:object) do described_class.new("testing", :user) end it "returns the binary data plus type" do expect(object.as_extended_json).to eq( { "$binary" => {'base64' => Base64.encode64("testing").strip, "subType" => '80' }} ) end it_behaves_like 'an Extended JSON serializable object' it_behaves_like '#as_json calls #as_extended_json' 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 the 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::Error::InvalidBinaryType) expect(error.message).to match /is not a valid binary type/ } end end context 'when initialized via legacy YAML' do let(:yaml) { "--- !ruby/object:BSON::Binary\ndata: hello\ntype: :generic\n" } let(:deserialized) { YAML.safe_load(yaml, permitted_classes: [ Symbol, BSON::Binary ]) } it 'correctly sets the raw_type' do expect(deserialized.raw_type).to be == BSON::Binary::SUBTYPES[:generic] 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" [ { types: [ nil, 0, 0.chr, :generic, 'generic' ], bson: "#{7.to_bson}#{0.chr}testing", type: :generic, }, { types: [ 1, 1.chr, :function, 'function' ], bson: "#{7.to_bson}#{1.chr}testing", type: :function, }, { types: [ 2, 2.chr, :old, 'old' ], bson: "#{11.to_bson}#{2.chr}#{7.to_bson}testing", type: :old, }, { types: [ 3, 3.chr, :uuid_old, 'uuid_old' ], bson: "#{7.to_bson}#{3.chr}testing", type: :uuid_old, }, { types: [ 4, 4.chr, :uuid, 'uuid' ], bson: "#{7.to_bson}#{4.chr}testing", type: :uuid, }, { types: [ 5, 5.chr, :md5, 'md5' ], bson: "#{7.to_bson}#{5.chr}testing", type: :md5, }, { types: [ 6, 6.chr, :ciphertext, 'ciphertext' ], bson: "#{7.to_bson}#{6.chr}testing", type: :ciphertext, }, { types: [ 0x80, 0x80.chr, :user, 'user' ], bson: "#{7.to_bson}#{128.chr}testing", type: :user, }, { types: [ 0xFF, 0xFF.chr ], bson: "#{7.to_bson}#{0xFF.chr}testing", type: :user, }, ].each do |defn| defn[:types].each do |type| context "when the type is #{type ? type.inspect : 'not provided'}" do let(:obj) do if type described_class.new("testing", type) else described_class.new("testing") end end let(:bson) { defn[:bson] } it_behaves_like "a serializable bson element" it_behaves_like "a deserializable bson element" it "reports its type as #{defn[:type].inspect}" do expect(obj.type).to be == defn[:type] end end end 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-5.2.0/spec/bson/binary_uuid_spec.rb000066400000000000000000000151251507420264200212100ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/bson/boolean_spec.rb000066400000000000000000000022521507420264200203120ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/bson/byte_buffer_read_spec.rb000066400000000000000000000074441507420264200221720ustar00rootroot00000000000000# rubocop:todo all require '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-5.2.0/spec/bson/byte_buffer_spec.rb000066400000000000000000000121671507420264200211750ustar00rootroot00000000000000# rubocop:todo all require '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-5.2.0/spec/bson/byte_buffer_write_spec.rb000066400000000000000000000477061507420264200224160ustar00rootroot00000000000000# rubocop:todo all require '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-5.2.0/spec/bson/code_spec.rb000066400000000000000000000025041507420264200176050ustar00rootroot00000000000000# rubocop:todo all # 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_extended_json" do let(:object) do described_class.new("this.value = 5") end it "returns the binary data plus type" do expect(object.as_extended_json).to eq({ "$code" => "this.value = 5" }) end it_behaves_like 'an Extended JSON serializable object' it_behaves_like '#as_json calls #as_extended_json' 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-5.2.0/spec/bson/code_with_scope_spec.rb000066400000000000000000000050031507420264200220260ustar00rootroot00000000000000# rubocop:todo all # 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_extended_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_extended_json).to eq( { "$code" => "this.value = val", "$scope" => { :val => "test" }} ) end it_behaves_like 'an Extended JSON serializable object' it_behaves_like '#as_json calls #as_extended_json' 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-5.2.0/spec/bson/config_spec.rb000066400000000000000000000001101507420264200201270ustar00rootroot00000000000000# rubocop:todo all require "spec_helper" describe BSON::Config do end bson-ruby-5.2.0/spec/bson/date_spec.rb000066400000000000000000000023541507420264200176130ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/bson/date_time_spec.rb000066400000000000000000000053271507420264200206340ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/bson/dbref_legacy_spec.rb000066400000000000000000000077061507420264200213120ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all 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. # For testing a class that emits warnings, without spamming the terminal # with them. def silenced_version_of(klass) Class.new(klass) do class < '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(BSON::Error::InvalidDBRefArgument) 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-5.2.0/spec/bson/dbref_spec.rb000066400000000000000000000301571507420264200177620ustar00rootroot00000000000000# frozen_string_literal: true # rubocop:todo all 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 InvalidDBRefArgument' do lambda do dbref end.should raise_error(BSON::Error::InvalidDBRefArgument) 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 InvalidDBRefArgument' do lambda do dbref end.should raise_error(BSON::Error::InvalidDBRefArgument) 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(BSON::Error::InvalidDBRefArgument, /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(BSON::Error::InvalidDBRefArgument, /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(BSON::Error::InvalidDBRefArgument, /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(BSON::Error::InvalidDBRefArgument, /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-5.2.0/spec/bson/decimal128_spec.rb000066400000000000000000001342631507420264200205340ustar00rootroot00000000000000# rubocop:todo all # 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 InvalidDecimal128Argument error' do expect { described_class.new(:invalid) }.to raise_exception(BSON::Error::InvalidDecimal128Argument, /A Decimal128 can only be created from a String or BigDecimal./ ) 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, mode: :bson) 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::Error::InvalidDecimal128Range, /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::Error::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, mode: :bson)['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 as a string" do expect(object.as_json).to eq('1.23') end %w[NaN -NaN SNaN -SNaN Infinity -Infinity].each do |value| context "when special value #{value}" do let(:object) do described_class.new(value) end it "returns nil to be consistent with ActiveSupport" do expect(object.as_json).to eq(nil) end end end it_behaves_like "a JSON serializable object" end describe "#as_extended_json" do let(:object) do described_class.new(BigDecimal('1.23')) end it "returns the decimal128 with $numberDecimal key" do expect(object.as_extended_json).to eq({ "$numberDecimal" => '1.23' }) end it_behaves_like "an Extended 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_d" 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_d).to eq(expected_big_decimal) end it 'permits the alias #to_big_decimal' 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 %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-5.2.0/spec/bson/document_as_spec.rb000066400000000000000000000032271507420264200211770ustar00rootroot00000000000000# rubocop:todo all # 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 describe '#deep_symbolize_keys!' do context 'string keys' do let(:doc) do described_class.new('foo' => 'bar') end it 'raises ArgumentError' do expect do doc.deep_symbolize_keys! end.to output(/\[DEPRECATION\] `deep_symbolize_keys!` is not supported on BSON::Document instances./).to_stderr end end end end bson-ruby-5.2.0/spec/bson/document_spec.rb000066400000000000000000000574601507420264200205240ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/bson/ext_json_parse_spec.rb000066400000000000000000000176421507420264200217270ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/bson/false_class_spec.rb000066400000000000000000000020061507420264200211470ustar00rootroot00000000000000# rubocop:todo all # 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 describe '#as_extended_json' do let(:object) { false } it_behaves_like '#as_extended_json returns self' it_behaves_like 'an Extended JSON serializable object' end end bson-ruby-5.2.0/spec/bson/float_spec.rb000066400000000000000000000034301507420264200177770ustar00rootroot00000000000000# rubocop:todo all # 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 let(:object) { 42.0 } context 'canonical mode' do it 'returns $numberDouble' do object.as_extended_json.should == {'$numberDouble' => '42.0'} end end context 'relaxed mode' do let(:serialized) do object.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 object.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 it_behaves_like "an Extended JSON serializable object" end end bson-ruby-5.2.0/spec/bson/hash_as_spec.rb000066400000000000000000000026211507420264200203010ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/bson/hash_spec.rb000066400000000000000000000245051507420264200176230ustar00rootroot00000000000000# rubocop:todo all # 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 dollar keys" do let(:obj) do { "$testing" => "value" } end 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 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 BigDecimal' do expect(from_bson).to eq({"x" => BigDecimal(1)}) end end context 'when deserializing round-tripping a Decimal128' do let(:to_bson) do {x:BSON::Decimal128.new('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 BigDecimal' do expect(from_bson).to eq({"x" => BigDecimal(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.to_not 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 expect(doc).to eq({ '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 expect(doc).to eq({ 'foo' => :bar }) end end context 'when deserializing a hash with a BigDecimal' do let(:to_bson) do {x: BigDecimal('1')}.to_bson end context 'when it has mode: :bson' do let(:from_bson) do Hash.from_bson(to_bson, mode: :bson) end it 'deserializes as a BigDecimal' do expect(from_bson).to eq({"x" => BSON::Decimal128.new('1')}) end end context 'when it doesn\'t have mode: :bson' do let(:from_bson) do Hash.from_bson(to_bson) end it 'deserializes as a BigDecimal' do expect(from_bson).to eq({"x" => BigDecimal(1)}) end end end end describe '#as_extended_json' do let(:object) do { 'foo' => :bar, 'baz' => ['qux', 1, 2.0, { 'lorem' => 1 }] } end let(:expected) do { "foo" => { "$symbol" => "bar" }, "baz" => [ "qux", { "$numberInt" => "1" }, { "$numberDouble" => "2.0" }, { "lorem" => { "$numberInt" => "1" } } ] } end it "returns the binary data plus type" do expect(object.as_extended_json).to eq(expected) end it_behaves_like 'an Extended JSON serializable object' end end bson-ruby-5.2.0/spec/bson/int32_spec.rb000066400000000000000000000145501507420264200176360ustar00rootroot00000000000000# rubocop:todo all # 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_json' do let(:object) { described_class.new(42) } it 'returns an Integer' do expect(object.as_json).to eq 42 end it_behaves_like "a JSON serializable object" end describe '#as_extended_json' do let(:object) { described_class.new(42) } context 'canonical mode' do it 'returns a Hash with key $numberInt' do expect(object.as_extended_json).to eq({ '$numberInt' => '42' }) end end context 'relaxed mode' do it 'returns an Integer' do expect(object.as_extended_json(mode: :relaxed)).to eq 42 end end context 'legacy mode' do it 'returns an Integer' do expect(object.as_extended_json(mode: :legacy)).to eq 42 end end it_behaves_like "an Extended JSON serializable object" end end bson-ruby-5.2.0/spec/bson/int64_spec.rb000066400000000000000000000170101507420264200176350ustar00rootroot00000000000000# rubocop:todo all # 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? && RUBY_VERSION < '3.0.0' 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? && RUBY_VERSION < '3.0.0' 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_json' do let(:object) { described_class.new(42) } it 'returns an Integer' do expect(object.as_json).to eq 42 end it_behaves_like "a JSON serializable object" end describe '#as_extended_json' do let(:object) { described_class.new(42) } context 'canonical mode' do it 'returns a Hash with key $numberLong' do expect(object.as_extended_json).to eq({ '$numberLong' => '42' }) end end context 'relaxed mode' do it 'returns an Integer' do expect(object.as_extended_json(mode: :relaxed)).to eq 42 end end context 'legacy mode' do it 'returns an Integer' do expect(object.as_extended_json(mode: :legacy)).to eq 42 end end it_behaves_like "an Extended JSON serializable object" end end bson-ruby-5.2.0/spec/bson/integer_spec.rb000066400000000000000000000063301507420264200203310ustar00rootroot00000000000000# rubocop:todo all # 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 '#as_json' do it 'returns an integer string' do expect(42.to_json).to eq '42' end end describe '#as_extended_json' do context 'when 32-bit representable' do let(:object) { 42 } context 'canonical mode' do it 'returns $numberInt when small' do expect(object.as_extended_json).to eq({ '$numberInt' => '42' }) end end context 'relaxed mode' do it 'returns integer' do expect(object.as_extended_json(mode: :relaxed)).to eq 42 end end context 'legacy mode' do it 'returns integer' do expect(object.as_extended_json(mode: :legacy)).to eq 42 end end it_behaves_like "an Extended JSON serializable object" end context 'when not 32-bit representable' do let(:object) { 18014398241046527 } context 'canonical mode' do it 'returns $numberInt when small' do expect(object.as_extended_json).to eq({ '$numberLong' => '18014398241046527' }) end end context 'relaxed mode' do it 'returns integer' do expect(object.as_extended_json(mode: :relaxed)).to eq 18014398241046527 end end context 'legacy mode' do it 'returns integer' do expect(object.as_extended_json(mode: :legacy)).to eq 18014398241046527 end end it_behaves_like "an Extended JSON serializable object" end end end bson-ruby-5.2.0/spec/bson/json_spec.rb000066400000000000000000000023661507420264200176520ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/bson/max_key_spec.rb000066400000000000000000000035011507420264200203260ustar00rootroot00000000000000# rubocop:todo all # 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_extended_json" do let(:object) do described_class.new end it "returns the binary data plus type" do expect(object.as_extended_json).to eq({ "$maxKey" => 1 }) end it_behaves_like 'an Extended JSON serializable object' it_behaves_like '#as_json calls #as_extended_json' 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-5.2.0/spec/bson/min_key_spec.rb000066400000000000000000000035011507420264200203240ustar00rootroot00000000000000# rubocop:todo all # 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_extended_json" do let(:object) do described_class.new end it "returns the binary data plus type" do expect(object.as_extended_json).to eq({ "$minKey" => 1 }) end it_behaves_like 'an Extended JSON serializable object' it_behaves_like '#as_json calls #as_extended_json' 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-5.2.0/spec/bson/nil_class_spec.rb000066400000000000000000000016261507420264200206460ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/bson/object_id_spec.rb000066400000000000000000000324411507420264200206200ustar00rootroot00000000000000# rubocop:todo all # 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 as a string" do expect(object.as_json).to eq(object.to_s) end it_behaves_like "a JSON serializable object" end describe "#as_extended_json" do let(:object) do described_class.new end it "returns the object id with $oid key" do expect(object.as_extended_json).to eq({ "$oid" => object.to_s }) end 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::Error::InvalidObjectId) 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::Error::InvalidKey) end end context 'when the counter wraps' do before do BSON::ObjectId._generator.reset_counter(0xFFFFFF) end let(:before) { BSON::ObjectId.new } let(:after) { BSON::ObjectId.new } it 'resets the counter portion to 0' do expect(before._counter_part).to be == "ffffff" expect(after._counter_part).to be == "000000" end end context 'when the timestamp is larger than a 32-bit integer' do let(:distant_future) { Time.at(2 ** 32) } before do allow(Time).to receive(:now).and_return(distant_future) end let(:object_id) { BSON::ObjectId.new } it 'wraps the timestamp to 0' do expect(object_id.to_time).to be == Time.at(0) end end context 'when fork changes the pid' do before do skip 'requires Process.fork' unless Process.respond_to?(:fork) end let(:parent_id) { BSON::ObjectId.new } let(:child_id) { Utils.perform_in_child { BSON::ObjectId.new } } it 'changes the process portion of the object-id' do expect(child_id._process_part).not_to be == parent_id._process_part end end end bson-ruby-5.2.0/spec/bson/object_spec.rb000066400000000000000000000015361507420264200201450ustar00rootroot00000000000000# rubocop:todo all # 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::Error::InvalidKey) end end end bson-ruby-5.2.0/spec/bson/open_struct_spec.rb000066400000000000000000000047001507420264200212400ustar00rootroot00000000000000# rubocop:todo all # 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 dollar keys" do let(:obj) do described_class.new({ "$testing" => "value" }) end 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 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-5.2.0/spec/bson/raw_spec.rb000066400000000000000000000353331507420264200174720ustar00rootroot00000000000000# rubocop:todo all require '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 "raises an error" do expect do object end.to raise_error(ArgumentError, /Regexp options must be a String or Symbol/) 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 "raises an error" do expect do serialized end.to raise_error(ArgumentError, /Regexp options must be a String or Symbol/) 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-5.2.0/spec/bson/regexp_spec.rb000066400000000000000000000110031507420264200201570ustar00rootroot00000000000000# rubocop:todo all # 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 "raises an error" do expect do regexp end.to raise_error(ArgumentError, /Regexp options must be a String or Symbol/) 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 or Symbol/) 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-5.2.0/spec/bson/registry_spec.rb000066400000000000000000000023471507420264200205500ustar00rootroot00000000000000# rubocop:todo all # 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::Error::UnsupportedType) end end end end bson-ruby-5.2.0/spec/bson/string_spec.rb000066400000000000000000000054541507420264200202100ustar00rootroot00000000000000# rubocop:todo all # 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::Error::InvalidObjectId) 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 let(:string) do "$testing.testing" end it "allows dots/dollars keys" do expect(string.to_bson_key).to eq(string) 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 describe '#as_extended_json' do let(:object) { 'Hello world!' } it_behaves_like '#as_extended_json returns self' it_behaves_like 'an Extended JSON serializable object' end end bson-ruby-5.2.0/spec/bson/symbol_raw_spec.rb000066400000000000000000000033541507420264200210550ustar00rootroot00000000000000# rubocop:todo all # 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 describe '#as_json' do let(:object) do described_class.new(:foobar) end it 'returns a string' do expect(object.as_json).to eq('foobar') end it_behaves_like 'a JSON serializable object' end describe '#as_extended_json' do let(:object) do described_class.new(:foobar) end it 'returns the binary data plus type' do expect(object.as_extended_json).to eq({ '$symbol' => 'foobar' }) end it_behaves_like 'an Extended JSON serializable object' end end bson-ruby-5.2.0/spec/bson/symbol_spec.rb000066400000000000000000000062721507420264200202060ustar00rootroot00000000000000# rubocop:todo all # 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 let(:symbol) do :'$testing.testing' end it "returns the key" do expect(symbol.to_bson_key).to eq(symbol) end end describe '#as_extended_json' do let(:object) do :foobar end it 'returns the binary data plus type' do expect(object.as_extended_json).to eq({ '$symbol' => 'foobar' }) end it_behaves_like 'an Extended JSON serializable object' end end bson-ruby-5.2.0/spec/bson/time_spec.rb000066400000000000000000000172061507420264200176360ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/bson/time_with_zone_spec.rb000066400000000000000000000043141507420264200217200ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/bson/timestamp_spec.rb000066400000000000000000000063511507420264200207020ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/bson/true_class_spec.rb000066400000000000000000000020031507420264200210310ustar00rootroot00000000000000# rubocop:todo all # 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 describe '#as_extended_json' do let(:object) { true } it_behaves_like '#as_extended_json returns self' it_behaves_like 'an Extended JSON serializable object' end end bson-ruby-5.2.0/spec/bson/undefined_spec.rb000066400000000000000000000026271507420264200206420ustar00rootroot00000000000000# rubocop:todo all # 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 describe "#as_json" do let(:object) do described_class.new end it "returns nil" do expect(object.as_json).to eq(nil) end it_behaves_like 'a JSON serializable object' end describe "#as_extended_json" do let(:object) do described_class.new end it "returns the binary data plus type" do expect(object.as_extended_json).to eq({ "$undefined" => true }) end it_behaves_like 'an Extended JSON serializable object' end end bson-ruby-5.2.0/spec/bson/vector_spec.rb000066400000000000000000000017661507420264200202060ustar00rootroot00000000000000# frozen_string_literal: true # Copyright (C) 2025-present 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::Vector do it 'behaves like an Array' do expect(described_class.new([ 1, 2, 3 ], :int8)).to be_a(Array) end describe '#initialize' do context 'when padding is not provided' do let(:vector) { described_class.new([ 1, 2, 3 ], :int8) } it 'sets the padding to 0' do expect(vector.padding).to eq(0) end end end end bson-ruby-5.2.0/spec/bson_spec.rb000066400000000000000000000026021507420264200166720ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/runners/000077500000000000000000000000001507420264200160665ustar00rootroot00000000000000bson-ruby-5.2.0/spec/runners/binary_vector.rb000066400000000000000000000034521507420264200212650ustar00rootroot00000000000000# frozen_string_literal: true require 'runners/common_driver' module BSON module BinaryVector class Spec < CommonDriver::Spec def initialize(file) super @valid = @invalid = nil end def tests @spec['tests'].collect do |test| BSON::BinaryVector::Test.new(self, test) end end def valid_tests tests.select(&:valid?) end def invalid_tests tests.reject(&:valid?) end end class Test attr_reader :canonical_bson, :description, :dtype, :padding, :vector def initialize(spec, test) @spec = spec @description = test['description'] @valid = test['valid'] @vector = ExtJSON.parse_obj(test['vector']) @dtype_hex = test['dtype_hex'] @dtype_alias = test['dtype_alias'] @dtype = @dtype_alias.downcase.to_sym @padding = test['padding'] @canonical_bson = test['canonical_bson'] end def valid? @valid end def document_from_canonical_bson bson_bytes = decode_hex(@canonical_bson) buffer = BSON::ByteBuffer.new(bson_bytes) BSON::Document.from_bson(buffer) end def canonical_bson_from_document(use_vector_type: false, validate_vector_data: false) args = if use_vector_type [ BSON::Vector.new(@vector, @dtype, @padding) ] else [ @vector, @dtype, @padding ] end { @spec.test_key => BSON::Binary.from_vector( *args, validate_vector_data: validate_vector_data ), }.to_bson.to_s end def bson decode_hex(@canonical_bson) end private def decode_hex(obj) [ obj ].pack('H*') end end end end bson-ruby-5.2.0/spec/runners/common_driver.rb000066400000000000000000000221451507420264200212620ustar00rootroot00000000000000# rubocop:todo all # 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_extended_json # # @return [ Hash ] The extended_json representation of document. # # @since 4.2.0 def document_as_extended_json { @test_key => object.as_extended_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, mode: :bson)) end end end end bson-ruby-5.2.0/spec/runners/corpus.rb000066400000000000000000000110031507420264200177210ustar00rootroot00000000000000# rubocop:todo all # 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 bson_type @bson_type ||= @spec['bson_type'].to_i(16).chr 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 :spec attr_reader :description, :string end end end bson-ruby-5.2.0/spec/runners/corpus_legacy.rb000066400000000000000000000172711507420264200212620ustar00rootroot00000000000000# rubocop:todo all # 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-5.2.0/spec/shared/000077500000000000000000000000001507420264200156405ustar00rootroot00000000000000bson-ruby-5.2.0/spec/spec_helper.rb000066400000000000000000000060321507420264200172110ustar00rootroot00000000000000# rubocop:todo all # 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 BINARY_VECTOR_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/binary_vector/*.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 "stringio" 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-5.2.0/spec/spec_tests/000077500000000000000000000000001507420264200165465ustar00rootroot00000000000000bson-ruby-5.2.0/spec/spec_tests/binary_vector_spec.rb000066400000000000000000000054721507420264200227630ustar00rootroot00000000000000# rubocop:todo all require 'spec_helper' require 'runners/binary_vector' describe 'Binary vector tests' do specs = BINARY_VECTOR_TESTS.map { |file| BSON::BinaryVector::Spec.new(file) } skipped_tests = [ 'Overflow Vector INT8', 'Underflow Vector INT8', 'INT8 with float inputs', 'Overflow Vector PACKED_BIT', 'Underflow Vector PACKED_BIT', 'Vector with float values PACKED_BIT' ] [true, false].each do |use_vector_type| context "use vector type: #{use_vector_type}" do specs.each do |spec| context(spec.description) do spec.valid_tests.each do |test| context(test.description) do it 'encodes a document' do expect(test.canonical_bson_from_document(use_vector_type: use_vector_type)).to eq(test.bson) end it 'decodes BSON' do binary = test.document_from_canonical_bson[spec.test_key] expect(binary.type).to eq(:vector) vector = binary.as_vector expect(vector.dtype).to eq(test.dtype) expect(vector.padding).to eq(test.padding) if vector.dtype == :float32 vector.each_with_index do |v, i| if v == Float::INFINITY || v == -Float::INFINITY expect(v).to eq(test.vector[i]) else expect(v).to be_within(0.00001).of(test.vector[i]) end end else expect(vector).to eq(test.vector) end end end end spec.invalid_tests.each do |test| context(test.description) do let(:subject) do if test.vector ->(vvd) { test.canonical_bson_from_document(use_vector_type: use_vector_type, validate_vector_data: vvd) } else ->() { test.document_from_canonical_bson } end end context 'with data validation' do it 'raises' do expect { subject.call(true) }.to raise_error do |err| expect([ArgumentError, BSON::Error]).to include(err.class) end end end context 'without data validation' do it 'raises' do skip 'Ruby Array.pack does not validate input' if skipped_tests.include?(test.description) expect { subject.call(false) }.to raise_error do |err| expect([ArgumentError, BSON::Error]).to include(err.class) end end end end end end end end end end bson-ruby-5.2.0/spec/spec_tests/common_driver_spec.rb000066400000000000000000000052051507420264200227520ustar00rootroot00000000000000# rubocop:todo all require '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 'serializes to a string', if: test.to_ext_json? do expect(test.document_as_extended_json).to eq(test.ext_json) end it 'creates the correct extended json document from the decoded object', if: test.to_ext_json? do expect(test.document_as_extended_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::Error::InvalidDecimal128String, BSON::Error::InvalidDecimal128Range, BSON::Error::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-5.2.0/spec/spec_tests/corpus_legacy_spec.rb000066400000000000000000000050341507420264200227460ustar00rootroot00000000000000# rubocop:todo all require '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-5.2.0/spec/spec_tests/corpus_spec.rb000066400000000000000000000104261507420264200214230ustar00rootroot00000000000000# rubocop:todo all require '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 # As per: # https://github.com/mongodb/specifications/blob/e7ee829329400786e01279b4f37d4e440d1e9cfa/source/bson-corpus/bson-corpus.rst#decimal128-type-0x13 # # Values under test must be parsed in a type-specific manner. let(:parsed_value) do case spec.bson_type when BSON::Decimal128::BSON_TYPE BSON::Decimal128.new(test.string) else BSON::ExtJSON.parse(test.string, mode: :bson) end 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_value end.to raise_error(Exception) end end end end end end bson-ruby-5.2.0/spec/spec_tests/data/000077500000000000000000000000001507420264200174575ustar00rootroot00000000000000bson-ruby-5.2.0/spec/spec_tests/data/binary_vector/000077500000000000000000000000001507420264200223255ustar00rootroot00000000000000bson-ruby-5.2.0/spec/spec_tests/data/binary_vector/README.md000066400000000000000000000061631507420264200236120ustar00rootroot00000000000000# Testing Binary subtype 9: Vector The JSON files in this directory tree are platform-independent tests that drivers can use to prove their conformance to the specification. These tests focus on the roundtrip of the list of numbers as input/output, along with their data type and byte padding. Additional tests exist in `bson_corpus/tests/binary.json` but do not sufficiently test the end-to-end process of Vector to BSON. For this reason, drivers must create a bespoke test runner for the vector subtype. ## Format The test data corpus consists of a JSON file for each data type (dtype). Each file contains a number of test cases, under the top-level key "tests". Each test case pertains to a single vector. The keys provide the specification of the vector. Valid cases also include the Canonical BSON format of a document {test_key: binary}. The "test_key" is common, and specified at the top level. #### Top level keys Each JSON file contains three top-level keys. - `description`: human-readable description of what is in the file - `test_key`: name used for key when encoding/decoding a BSON document containing the single BSON Binary for the test case. Applies to *every* case. - `tests`: array of test case objects, each of which have the following keys. Valid cases will also contain additional binary and json encoding values. #### Keys of individual tests cases - `description`: string describing the test. - `valid`: boolean indicating if the vector, dtype, and padding should be considered a valid input. - `vector`: (required if valid is true) list of numbers - `dtype_hex`: string defining the data type in hex (e.g. "0x10", "0x27") - `dtype_alias`: (optional) string defining the data dtype, perhaps as Enum. - `padding`: (optional) integer for byte padding. Defaults to 0. - `canonical_bson`: (required if valid is true) an (uppercase) big-endian hex representation of a BSON byte string. ## Required tests #### To prove correct in a valid case (`valid: true`), one MUST - encode a document from the numeric values, dtype, and padding, along with the "test_key", and assert this matches the canonical_bson string. - decode the canonical_bson into its binary form, and then assert that the numeric values, dtype, and padding all match those provided in the JSON. Note: For floating point number types, exact numerical matches may not be possible. Drivers that natively support the floating-point type being tested (e.g., when testing float32 vector values in a driver that natively supports float32), MUST assert that the input float array is the same after encoding and decoding. #### To prove correct in an invalid case (`valid:false`), one MUST - if the vector field is present, raise an exception when attempting to encode a document from the numeric values, dtype, and padding. - if the canonical_bson field is present, raise an exception when attempting to deserialize it into the corresponding numeric values, as the field contains corrupted data. ## FAQ - What MongoDB Server version does this apply to? - Files in the "specifications" repository have no version scheme. They are not tied to a MongoDB server version. bson-ruby-5.2.0/spec/spec_tests/data/binary_vector/float32.json000066400000000000000000000037501507420264200244770ustar00rootroot00000000000000{ "description": "Tests of Binary subtype 9, Vectors, with dtype FLOAT32", "test_key": "vector", "tests": [ { "description": "Simple Vector FLOAT32", "valid": true, "vector": [127.0, 7.0], "dtype_hex": "0x27", "dtype_alias": "FLOAT32", "padding": 0, "canonical_bson": "1C00000005766563746F72000A0000000927000000FE420000E04000" }, { "description": "Vector with decimals and negative value FLOAT32", "valid": true, "vector": [127.7, -7.7], "dtype_hex": "0x27", "dtype_alias": "FLOAT32", "padding": 0, "canonical_bson": "1C00000005766563746F72000A0000000927006666FF426666F6C000" }, { "description": "Empty Vector FLOAT32", "valid": true, "vector": [], "dtype_hex": "0x27", "dtype_alias": "FLOAT32", "padding": 0, "canonical_bson": "1400000005766563746F72000200000009270000" }, { "description": "Infinity Vector FLOAT32", "valid": true, "vector": [{"$numberDouble": "-Infinity"}, 0.0, {"$numberDouble": "Infinity"} ], "dtype_hex": "0x27", "dtype_alias": "FLOAT32", "padding": 0, "canonical_bson": "2000000005766563746F72000E000000092700000080FF000000000000807F00" }, { "description": "FLOAT32 with padding", "valid": false, "vector": [127.0, 7.0], "dtype_hex": "0x27", "dtype_alias": "FLOAT32", "padding": 3, "canonical_bson": "1C00000005766563746F72000A0000000927030000FE420000E04000" }, { "description": "Insufficient vector data with 3 bytes FLOAT32", "valid": false, "dtype_hex": "0x27", "dtype_alias": "FLOAT32", "canonical_bson": "1700000005766563746F7200050000000927002A2A2A00" }, { "description": "Insufficient vector data with 5 bytes FLOAT32", "valid": false, "dtype_hex": "0x27", "dtype_alias": "FLOAT32", "canonical_bson": "1900000005766563746F7200070000000927002A2A2A2A2A00" } ] } bson-ruby-5.2.0/spec/spec_tests/data/binary_vector/int8.json000066400000000000000000000025721507420264200241100ustar00rootroot00000000000000{ "description": "Tests of Binary subtype 9, Vectors, with dtype INT8", "test_key": "vector", "tests": [ { "description": "Simple Vector INT8", "valid": true, "vector": [127, 7], "dtype_hex": "0x03", "dtype_alias": "INT8", "padding": 0, "canonical_bson": "1600000005766563746F7200040000000903007F0700" }, { "description": "Empty Vector INT8", "valid": true, "vector": [], "dtype_hex": "0x03", "dtype_alias": "INT8", "padding": 0, "canonical_bson": "1400000005766563746F72000200000009030000" }, { "description": "Overflow Vector INT8", "valid": false, "vector": [128], "dtype_hex": "0x03", "dtype_alias": "INT8", "padding": 0 }, { "description": "Underflow Vector INT8", "valid": false, "vector": [-129], "dtype_hex": "0x03", "dtype_alias": "INT8", "padding": 0 }, { "description": "INT8 with padding", "valid": false, "vector": [127, 7], "dtype_hex": "0x03", "dtype_alias": "INT8", "padding": 3, "canonical_bson": "1600000005766563746F7200040000000903037F0700" }, { "description": "INT8 with float inputs", "valid": false, "vector": [127.77, 7.77], "dtype_hex": "0x03", "dtype_alias": "INT8", "padding": 0 } ] } bson-ruby-5.2.0/spec/spec_tests/data/binary_vector/packed_bit.json000066400000000000000000000042441507420264200253110ustar00rootroot00000000000000{ "description": "Tests of Binary subtype 9, Vectors, with dtype PACKED_BIT", "test_key": "vector", "tests": [ { "description": "Padding specified with no vector data PACKED_BIT", "valid": false, "vector": [], "dtype_hex": "0x10", "dtype_alias": "PACKED_BIT", "padding": 1, "canonical_bson": "1400000005766563746F72000200000009100100" }, { "description": "Simple Vector PACKED_BIT", "valid": true, "vector": [127, 7], "dtype_hex": "0x10", "dtype_alias": "PACKED_BIT", "padding": 0, "canonical_bson": "1600000005766563746F7200040000000910007F0700" }, { "description": "Empty Vector PACKED_BIT", "valid": true, "vector": [], "dtype_hex": "0x10", "dtype_alias": "PACKED_BIT", "padding": 0, "canonical_bson": "1400000005766563746F72000200000009100000" }, { "description": "PACKED_BIT with padding", "valid": true, "vector": [127, 7], "dtype_hex": "0x10", "dtype_alias": "PACKED_BIT", "padding": 3, "canonical_bson": "1600000005766563746F7200040000000910037F0700" }, { "description": "Overflow Vector PACKED_BIT", "valid": false, "vector": [256], "dtype_hex": "0x10", "dtype_alias": "PACKED_BIT", "padding": 0 }, { "description": "Underflow Vector PACKED_BIT", "valid": false, "vector": [-1], "dtype_hex": "0x10", "dtype_alias": "PACKED_BIT", "padding": 0 }, { "description": "Vector with float values PACKED_BIT", "valid": false, "vector": [127.5], "dtype_hex": "0x10", "dtype_alias": "PACKED_BIT", "padding": 0 }, { "description": "Exceeding maximum padding PACKED_BIT", "valid": false, "vector": [1], "dtype_hex": "0x10", "dtype_alias": "PACKED_BIT", "padding": 8, "canonical_bson": "1500000005766563746F7200030000000910080100" }, { "description": "Negative padding PACKED_BIT", "valid": false, "vector": [1], "dtype_hex": "0x10", "dtype_alias": "PACKED_BIT", "padding": -1 } ] } bson-ruby-5.2.0/spec/spec_tests/data/corpus/000077500000000000000000000000001507420264200207725ustar00rootroot00000000000000bson-ruby-5.2.0/spec/spec_tests/data/corpus/README.md000066400000000000000000000012031507420264200222450ustar00rootroot00000000000000There 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-5.2.0/spec/spec_tests/data/corpus/array.json000066400000000000000000000037461507420264200230150ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/binary.json000066400000000000000000000161271507420264200231600ustar00rootroot00000000000000{ "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 0x08", "canonical_bson": "1D000000057800100000000873FFD26444B34C6990E8E7D1DFC035D400", "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"08\"}}}" }, { "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\"}}}" }, { "description": "subtype 0x09 Vector FLOAT32", "canonical_bson": "170000000578000A0000000927000000FE420000E04000", "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"JwAAAP5CAADgQA==\", \"subType\": \"09\"}}}" }, { "description": "subtype 0x09 Vector INT8", "canonical_bson": "11000000057800040000000903007F0700", "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"AwB/Bw==\", \"subType\": \"09\"}}}" }, { "description": "subtype 0x09 Vector PACKED_BIT", "canonical_bson": "11000000057800040000000910007F0700", "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"EAB/Bw==\", \"subType\": \"09\"}}}" }, { "description": "subtype 0x09 Vector (Zero-length) FLOAT32", "canonical_bson": "0F0000000578000200000009270000", "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"JwA=\", \"subType\": \"09\"}}}" }, { "description": "subtype 0x09 Vector (Zero-length) INT8", "canonical_bson": "0F0000000578000200000009030000", "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"AwA=\", \"subType\": \"09\"}}}" }, { "description": "subtype 0x09 Vector (Zero-length) PACKED_BIT", "canonical_bson": "0F0000000578000200000009100000", "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"EAA=\", \"subType\": \"09\"}}}" } ], "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-5.2.0/spec/spec_tests/data/corpus/boolean.json000066400000000000000000000012551507420264200233070ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/code.json000066400000000000000000000046521507420264200226060ustar00rootroot00000000000000{ "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": "190000000D61000D000000C3A9C3A9C3A9C3A9C3A9C3A90000", "canonical_extjson": "{\"a\" : {\"$code\" : \"\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\"}}" }, { "description": "three-byte UTF-8 (\u2606)", "canonical_bson": "190000000D61000D000000E29886E29886E29886E298860000", "canonical_extjson": "{\"a\" : {\"$code\" : \"\\u2606\\u2606\\u2606\\u2606\"}}" }, { "description": "Embedded nulls", "canonical_bson": "190000000D61000D0000006162006261620062616261620000", "canonical_extjson": "{\"a\" : {\"$code\" : \"ab\\u0000bab\\u0000babab\"}}" } ], "decodeErrors": [ { "description": "bad code string length: 0 (but no 0x00 either)", "bson": "0C0000000D61000000000000" }, { "description": "bad code string length: -1", "bson": "0C0000000D6100FFFFFFFF00" }, { "description": "bad code string length: eats terminator", "bson": "100000000D6100050000006200620000" }, { "description": "bad code string length: longer than rest of document", "bson": "120000000D00FFFFFF00666F6F6261720000" }, { "description": "code string is not null-terminated", "bson": "100000000D610004000000616263FF00" }, { "description": "empty code string, but extra null", "bson": "0E0000000D610001000000000000" }, { "description": "invalid UTF-8", "bson": "0E0000000D610002000000E90000" } ] } bson-ruby-5.2.0/spec/spec_tests/data/corpus/code_w_scope.json000066400000000000000000000067741507420264200243340ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/datetime.json000066400000000000000000000032561507420264200234670ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/dbpointer.json000066400000000000000000000054031507420264200236550ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/dbref.json000066400000000000000000000067661507420264200227660ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/decimal128-1.json000066400000000000000000000431051507420264200236570ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/decimal128-2.json000066400000000000000000001136001507420264200236560ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/decimal128-3.json000066400000000000000000002613321507420264200236650ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/decimal128-4.json000066400000000000000000000157371507420264200236740ustar00rootroot00000000000000{ "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" }, { "description": "[dqbas939] overflow results at different rounding modes (Overflow & Inexact & Rounded)", "string": "-7e10000" }, { "description": "[dqbsr534] negatives (Rounded & Inexact)", "string": "-1.11111111111111111111111111111234650" }, { "description": "[dqbsr535] negatives (Rounded & Inexact)", "string": "-1.11111111111111111111111111111234551" }, { "description": "[dqbsr533] negatives (Rounded & Inexact)", "string": "-1.11111111111111111111111111111234550" }, { "description": "[dqbsr532] negatives (Rounded & Inexact)", "string": "-1.11111111111111111111111111111234549" }, { "description": "[dqbsr432] check rounding modes heeded (Rounded & Inexact)", "string": "1.11111111111111111111111111111234549" }, { "description": "[dqbsr433] check rounding modes heeded (Rounded & Inexact)", "string": "1.11111111111111111111111111111234550" }, { "description": "[dqbsr435] check rounding modes heeded (Rounded & Inexact)", "string": "1.11111111111111111111111111111234551" }, { "description": "[dqbsr434] check rounding modes heeded (Rounded & Inexact)", "string": "1.11111111111111111111111111111234650" }, { "description": "[dqbas938] overflow results at different rounding modes (Overflow & Inexact & Rounded)", "string": "7e10000" }, { "description": "Inexact rounding#1", "string": "100000000000000000000000000000000000000000000000000000000001" }, { "description": "Inexact rounding#2", "string": "1E-6177" } ] } bson-ruby-5.2.0/spec/spec_tests/data/corpus/decimal128-5.json000066400000000000000000000554551507420264200236760ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/decimal128-6.json000066400000000000000000000060111507420264200236570ustar00rootroot00000000000000{ "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": "leading white space positive number", "string": " 1" }, { "description": "leading white space negative number", "string": " -1" }, { "description": "trailing white space", "string": "1 " }, { "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-5.2.0/spec/spec_tests/data/corpus/decimal128-7.json000066400000000000000000000310171507420264200236640ustar00rootroot00000000000000{ "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": "[basx512] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", "string": "12 " }, { "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-5.2.0/spec/spec_tests/data/corpus/document.json000066400000000000000000000043741507420264200235130ustar00rootroot00000000000000{ "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\"}}" }, { "description": "Dollar-prefixed key in sub-document", "canonical_bson": "170000000378000F000000022461000200000062000000", "canonical_extjson": "{\"x\" : {\"$a\" : \"b\"}}" }, { "description": "Dollar as key in sub-document", "canonical_bson": "160000000378000E0000000224000200000061000000", "canonical_extjson": "{\"x\" : {\"$\" : \"a\"}}" }, { "description": "Dotted key in sub-document", "canonical_bson": "180000000378001000000002612E62000200000063000000", "canonical_extjson": "{\"x\" : {\"a.b\" : \"c\"}}" }, { "description": "Dot as key in sub-document", "canonical_bson": "160000000378000E000000022E000200000061000000", "canonical_extjson": "{\"x\" : {\".\" : \"a\"}}" } ], "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-5.2.0/spec/spec_tests/data/corpus/double.json000066400000000000000000000067071507420264200231510ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/int32.json000066400000000000000000000026271507420264200226330ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/int64.json000066400000000000000000000027621507420264200226400ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/maxkey.json000066400000000000000000000004231507420264200231620ustar00rootroot00000000000000{ "description": "Maxkey type", "bson_type": "0x7F", "test_key": "a", "valid": [ { "description": "Maxkey", "canonical_bson": "080000007F610000", "canonical_extjson": "{\"a\" : {\"$maxKey\" : 1}}" } ] } bson-ruby-5.2.0/spec/spec_tests/data/corpus/minkey.json000066400000000000000000000004231507420264200231600ustar00rootroot00000000000000{ "description": "Minkey type", "bson_type": "0xFF", "test_key": "a", "valid": [ { "description": "Minkey", "canonical_bson": "08000000FF610000", "canonical_extjson": "{\"a\" : {\"$minKey\" : 1}}" } ] } bson-ruby-5.2.0/spec/spec_tests/data/corpus/multi-type-deprecated.json000066400000000000000000000124541507420264200261020ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/multi-type.json000066400000000000000000000046451507420264200240070ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/null.json000066400000000000000000000004021507420264200226330ustar00rootroot00000000000000{ "description": "Null type", "bson_type": "0x0A", "test_key": "a", "valid": [ { "description": "Null", "canonical_bson": "080000000A610000", "canonical_extjson": "{\"a\" : null}" } ] } bson-ruby-5.2.0/spec/spec_tests/data/corpus/oid.json000066400000000000000000000016221507420264200224410ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/regex.json000066400000000000000000000062011507420264200227760ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/string.json000066400000000000000000000053741507420264200232040ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/symbol.json000066400000000000000000000062401507420264200231740ustar00rootroot00000000000000{ "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": "0C0000000E61000000000000" }, { "description": "bad symbol length: -1", "bson": "0C0000000E6100FFFFFFFF00" }, { "description": "bad symbol length: eats terminator", "bson": "100000000E6100050000006200620000" }, { "description": "bad symbol length: longer than rest of document", "bson": "120000000E00FFFFFF00666F6F6261720000" }, { "description": "symbol is not null-terminated", "bson": "100000000E610004000000616263FF00" }, { "description": "empty symbol, but extra null", "bson": "0E0000000E610001000000000000" }, { "description": "invalid UTF-8", "bson": "0E0000000E610002000000E90000" } ] } bson-ruby-5.2.0/spec/spec_tests/data/corpus/timestamp.json000066400000000000000000000026651507420264200237010ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus/top.json000066400000000000000000000243521507420264200224750ustar00rootroot00000000000000{ "description": "Top-level document validity", "bson_type": "0x00", "valid": [ { "description": "Dollar-prefixed key in top-level document", "canonical_bson": "0F00000010246B6579002A00000000", "canonical_extjson": "{\"$key\": {\"$numberInt\": \"42\"}}" }, { "description": "Dollar as key in top-level document", "canonical_bson": "0E00000002240002000000610000", "canonical_extjson": "{\"$\": \"a\"}" }, { "description": "Dotted key in top-level document", "canonical_bson": "1000000002612E620002000000630000", "canonical_extjson": "{\"a.b\": \"c\"}" }, { "description": "Dot as key in top-level document", "canonical_bson": "0E000000022E0002000000610000", "canonical_extjson": "{\".\": \"a\"}" } ], "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-5.2.0/spec/spec_tests/data/corpus/undefined.json000066400000000000000000000006511507420264200236300ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/000077500000000000000000000000001507420264200223165ustar00rootroot00000000000000bson-ruby-5.2.0/spec/spec_tests/data/corpus_legacy/array.json000066400000000000000000000034211507420264200243270ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/binary.json000066400000000000000000000050231507420264200244750ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/boolean.json000066400000000000000000000012051507420264200246260ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/code.json000066400000000000000000000043751507420264200241340ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/code_w_scope.json000066400000000000000000000065371507420264200256550ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/document.json000066400000000000000000000022401507420264200250250ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/double.json000066400000000000000000000037361507420264200244740ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/failures/000077500000000000000000000000001507420264200241305ustar00rootroot00000000000000bson-ruby-5.2.0/spec/spec_tests/data/corpus_legacy/failures/datetime.json000066400000000000000000000021341507420264200266170ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/failures/dbpointer.json000066400000000000000000000025701507420264200270150ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/failures/int64.json000066400000000000000000000022021507420264200257630ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/failures/symbol.json000066400000000000000000000035561507420264200263410ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/int32.json000066400000000000000000000017101507420264200241470ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/maxkey.json000066400000000000000000000003721507420264200245110ustar00rootroot00000000000000{ "description": "MaxKey", "bson_type": "0xFF", "test_key": "a", "valid": [ { "description": "Maxkey", "bson": "080000007F610000", "extjson": "{\"a\" : {\"$maxKey\" : 1}}" } ] } bson-ruby-5.2.0/spec/spec_tests/data/corpus_legacy/minkey.json000066400000000000000000000003721507420264200245070ustar00rootroot00000000000000{ "description": "MinKey", "bson_type": "0xFF", "test_key": "a", "valid": [ { "description": "Minkey", "bson": "08000000FF610000", "extjson": "{\"a\" : {\"$minKey\" : 1}}" } ] } bson-ruby-5.2.0/spec/spec_tests/data/corpus_legacy/null.json000066400000000000000000000003551507420264200241660ustar00rootroot00000000000000{ "description": "NilClass", "bson_type": "0x0A", "test_key": "a", "valid": [ { "description": "Null", "bson": "080000000A610000", "extjson": "{\"a\" : null}" } ] } bson-ruby-5.2.0/spec/spec_tests/data/corpus_legacy/oid.json000066400000000000000000000015261507420264200237700ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/regex.json000066400000000000000000000022601507420264200243230ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/string.json000066400000000000000000000042671507420264200245300ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/timestamp.json000066400000000000000000000007401507420264200252150ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/top.json000066400000000000000000000042771507420264200240250ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/corpus_legacy/undefined.json000066400000000000000000000004601507420264200251520ustar00rootroot00000000000000{ "description": "Undefined type (deprecated)", "bson_type": "0x06", "deprecated": true, "test_key": "a", "valid": [ { "description": "Undefined", "bson": "0800000006610000", "extjson": "{\"a\" : {\"$undefined\" : true}}" } ] } bson-ruby-5.2.0/spec/spec_tests/data/decimal128/000077500000000000000000000000001507420264200213105ustar00rootroot00000000000000bson-ruby-5.2.0/spec/spec_tests/data/decimal128/decimal128-1.json000066400000000000000000000422331507420264200241760ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/decimal128/decimal128-2.json000066400000000000000000000727051507420264200242060ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/decimal128/decimal128-3.json000066400000000000000000001754161507420264200242120ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/decimal128/decimal128-4.json000066400000000000000000000135721507420264200242050ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/decimal128/decimal128-5.json000066400000000000000000000413371507420264200242060ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/decimal128/decimal128-6.json000066400000000000000000000060501507420264200242000ustar00rootroot00000000000000{ "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-5.2.0/spec/spec_tests/data/decimal128/decimal128-7.json000066400000000000000000000311371507420264200242050ustar00rootroot00000000000000{ "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-5.2.0/spec/support/000077500000000000000000000000001507420264200161065ustar00rootroot00000000000000bson-ruby-5.2.0/spec/support/shared_examples.rb000066400000000000000000000073521507420264200216060ustar00rootroot00000000000000# rubocop:todo all # 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 "an Extended JSON serializable object" do it "serializes the Extended JSON from #as_extended_json" do expect(object.to_extended_json).to eq(object.as_extended_json.to_json) end end shared_examples_for '#as_extended_json returns self' do it 'returns self' do expect(object.as_extended_json).to eq(object) end end shared_examples_for '#as_json calls #as_extended_json' do it 'calls #as_extended_json' do expect(object).to receive(:as_extended_json).with(no_args) object.as_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 has dots/dollars" do context "when the string starts with $" do let(:string) do "$testing" end it "does not raise an exception" do expect { validated }.to_not raise_error end end context "when the string contains a ." do let(:string) do "testing.testing" end it "does not raise an exception" do expect { validated }.to_not raise_error end end end end bson-ruby-5.2.0/spec/support/spec_config.rb000066400000000000000000000005311507420264200207110ustar00rootroot00000000000000# rubocop:todo all require '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-5.2.0/spec/support/utils.rb000066400000000000000000000031201507420264200175670ustar00rootroot00000000000000# rubocop:todo all module Utils extend self # 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. def make_byte_string(char_array, encoding = 'BINARY') char_array.map do |char| char.chr.force_encoding('BINARY') end.join.force_encoding(encoding) end # Forks the current process and executes the given block in the child. # The value returned by the block is then returned in the parent process # by this method. # # @return [ Object ] the value returned by the block def perform_in_child(&block) reader, writer = IO.pipe if fork parent_worker(reader, writer) else child_worker(reader, writer, &block) end end private # A utility method for #perform_in_child, to handle tasks for the parent # side of the fork. # # @param [ IO ] reader The reader IO for the pipe # @param [ IO ] writer The writer IO for the pipe # # @return [ Object ] the value returned by the child process def parent_worker(reader, writer) writer.close blob = reader.read reader.close Process.wait Marshal.load(blob) end # A utility method for #perform_in_child, to handle tasks for the child # side of the fork. # # @param [ IO ] reader The reader IO for the pipe # @param [ IO ] writer The writer IO for the pipe def child_worker(reader, writer, &block) reader.close result = block.call writer.write Marshal.dump(result) writer.close exit! 0 end end bson-ruby-5.2.0/src/000077500000000000000000000000001507420264200142275ustar00rootroot00000000000000bson-ruby-5.2.0/src/main/000077500000000000000000000000001507420264200151535ustar00rootroot00000000000000bson-ruby-5.2.0/src/main/org/000077500000000000000000000000001507420264200157425ustar00rootroot00000000000000bson-ruby-5.2.0/src/main/org/bson_ruby/000077500000000000000000000000001507420264200177445ustar00rootroot00000000000000bson-ruby-5.2.0/src/main/org/bson_ruby/ByteBuf.java000066400000000000000000000520051507420264200221510ustar00rootroot00000000000000/* * 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_ruby; 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(RubyNumeric.num2long(value)); 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-5.2.0/src/main/org/bson_ruby/GeneratorExtension.java000066400000000000000000000134711507420264200244400ustar00rootroot00000000000000/* * 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_ruby; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.SecureRandom; 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.RubyNumeric; 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 BSON module name.. * * @since 2.0.0 */ private static final String BSON = "BSON".intern(); /** * 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()); /** * A random value, unique to this process. */ private static byte[] randomValue = new byte[5]; /** * A flag indicating whether the random value has been generated for the * process or not. */ private static boolean randomValueGenerated = false; /** * 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.getClass(OBJECT_ID); RubyClass generator = objectId.getClass(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", "next_object_id" }) public static IRubyObject next(final IRubyObject generator) { RubyModule bson = generator.getRuntime().getModule(BSON); RubyClass objectId = bson.getClass(OBJECT_ID); return nextObjectId(generator, (int) RubyNumeric.num2long(objectId.callMethod("timestamp"))); } /** * 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", "next_object_id" }) public static IRubyObject next(final IRubyObject generator, final IRubyObject time) { return nextObjectId(generator, (int) (RubyNumeric.num2long(time) / 1000)); } /** * Reset the counter to zero. This is used only by tests. * * @param generator The generator instance. * @param value The integer value to set the counter to. * * @api private */ @JRubyMethod(name = { "reset_counter" }) public static IRubyObject resetCounter(final IRubyObject generator) { counter.set(0); return generator; } /** * Reset the counter. This is used only by tests. * * @param generator The generator instance. * @param value The integer value to set the counter to. * * @api private */ @JRubyMethod(name = { "reset_counter" }) public static IRubyObject resetCounter(final IRubyObject generator, final IRubyObject value) { counter.set((int) RubyNumeric.num2long(value)); return generator; } /** * Generate the next object id in the sequence, per the ObjectId spec: * https://github.com/mongodb/specifications/blob/master/source/bson-objectid/objectid.md#specification * * @param generator The object id generator. * @param time The time in seconds. * * @return The object id raw bytes. */ private static IRubyObject nextObjectId(final IRubyObject generator, final int time) { final ByteBuffer buffer = ByteBuffer.allocate(12).order(ByteOrder.BIG_ENDIAN); // a 4-byte value representing the seconds since the Unix epoch in the highest order bytes, buffer.putInt(time); // a 5-byte random number unique to a machine and process, buffer.put(uniqueIdentifier()); // a 3-byte counter, starting with a random value. buffer.put(counterBytes()); return RubyString.newString(generator.getRuntime(), buffer.array()); } /** * Get the 5-byte random number for the current process. If the value has * not yet been generated for the process, or if the process id has changed, * the value will be generated first. * * @return The 5-byte array */ private static byte[] uniqueIdentifier() { if (!randomValueGenerated) { randomValueGenerated = true; new SecureRandom().nextBytes(randomValue); } return randomValue; } /** * Get the next value of the counter as a 3-byte array (big-endian). This * will increment the counter. * * @return A 3-byte array representation of the next counter value. */ private static byte[] counterBytes() { byte[] bytes = new byte[3]; ByteBuffer buffer = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN); buffer.putInt(counter.getAndIncrement() << 8); buffer.rewind(); buffer.get(bytes); return bytes; } } bson-ruby-5.2.0/src/main/org/bson_ruby/NativeService.java000066400000000000000000000036161507420264200233640ustar00rootroot00000000000000/* * 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_ruby; 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.getModule(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; } }