Merge branch 'main' into anton--7392--fix-map-key-nit

pull/16567/head
Anton Grbin 10 months ago
commit d992b8a2a6
  1. 10
      .bcr/presubmit.yml
  2. 6
      .github/workflows/staleness_check.yml
  3. 67
      .github/workflows/test_bazel.yml
  4. 64
      .github/workflows/test_cpp.yml
  5. 18
      .github/workflows/test_csharp.yml
  6. 14
      .github/workflows/test_java.yml
  7. 14
      .github/workflows/test_objectivec.yml
  8. 30
      .github/workflows/test_php.yml
  9. 6
      .github/workflows/test_php_ext.yml
  10. 8
      .github/workflows/test_python.yml
  11. 24
      .github/workflows/test_ruby.yml
  12. 12
      .github/workflows/test_runner.yml
  13. 6
      .github/workflows/test_rust.yml
  14. 24
      .github/workflows/test_upb.yml
  15. 72
      Cargo.bazel.lock
  16. 14
      Cargo.lock
  17. 3
      MODULE.bazel
  18. 25
      WORKSPACE
  19. 17
      bazel/system_python.bzl
  20. 16
      build_defs/BUILD.bazel
  21. 3
      ci/Windows.bazelrc
  22. 1
      ci/macOS.bazelrc
  23. 9
      cmake/protobuf-config-version.cmake.in
  24. 20
      compatibility/BUILD.bazel
  25. 53
      compatibility/runtime_conformance.bzl
  26. 3
      conformance/BUILD.bazel
  27. 4
      conformance/conformance_dart.dart
  28. 214
      conformance/conformance_php.php
  29. 7
      conformance/test_protos/test_messages_edition2023.proto
  30. 287
      conformance/text_format_conformance_suite.cc
  31. 21
      conformance/text_format_failure_list_java.txt
  32. 8
      conformance/text_format_failure_list_php.txt
  33. 96
      conformance/text_format_failure_list_python.txt
  34. 72
      conformance/text_format_failure_list_python_cpp.txt
  35. 72
      conformance/text_format_failure_list_python_upb.txt
  36. 36
      csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
  37. 10
      csharp/src/Google.Protobuf.Test/Reflection/DescriptorDeclarationTest.cs
  38. 8
      csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs
  39. BIN
      csharp/src/Google.Protobuf.Test/testprotos.pb
  40. 5
      csharp/src/Google.Protobuf/JsonFormatter.cs
  41. 9
      csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
  42. 7
      csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
  43. 3
      docs/design/editions/README.md
  44. 401
      docs/design/editions/group-migration-issues.md
  45. 1
      docs/third_party.md
  46. 30
      editions/BUILD
  47. 14
      editions/golden/compare_cpp_codegen_failure.txt
  48. 4
      editions/golden/compare_cpp_codegen_failure.xml
  49. 2
      editions/golden/editions_transform_proto2.proto
  50. 10
      examples/.bazelrc
  51. 53
      java/README.md
  52. 4
      java/core/BUILD.bazel
  53. 2
      java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
  54. 3
      java/core/src/main/java/com/google/protobuf/CodedInputStream.java
  55. 449
      java/core/src/main/java/com/google/protobuf/CodedOutputStreamWriter.java
  56. 79
      java/core/src/main/java/com/google/protobuf/DebugFormat.java
  57. 8
      java/core/src/main/java/com/google/protobuf/Descriptors.java
  58. 2
      java/core/src/main/java/com/google/protobuf/ExtensionSchemas.java
  59. 11
      java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
  60. 2
      java/core/src/main/java/com/google/protobuf/IntArrayList.java
  61. 30
      java/core/src/main/java/com/google/protobuf/Internal.java
  62. 153
      java/core/src/main/java/com/google/protobuf/ListFieldSchema.java
  63. 99
      java/core/src/main/java/com/google/protobuf/ListFieldSchemaFull.java
  64. 59
      java/core/src/main/java/com/google/protobuf/ListFieldSchemaLite.java
  65. 33
      java/core/src/main/java/com/google/protobuf/ListFieldSchemas.java
  66. 58
      java/core/src/main/java/com/google/protobuf/ManifestSchemaFactory.java
  67. 2
      java/core/src/main/java/com/google/protobuf/MapFieldSchemaFull.java
  68. 2
      java/core/src/main/java/com/google/protobuf/MapFieldSchemaLite.java
  69. 2
      java/core/src/main/java/com/google/protobuf/MapFieldSchemas.java
  70. 2
      java/core/src/main/java/com/google/protobuf/NewInstanceSchemas.java
  71. 20
      java/core/src/main/java/com/google/protobuf/RuntimeVersion.java
  72. 44
      java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
  73. 210
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  74. 44
      java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
  75. 210
      java/core/src/test/java/com/google/protobuf/DebugFormatTest.java
  76. 10
      java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
  77. 5
      java/core/src/test/proto/com/google/protobuf/test_check_utf8.proto
  78. 28
      java/kotlin/src/test/kotlin/com/google/protobuf/Proto2Test.kt
  79. 14
      java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt
  80. 9
      java/kotlin/src/test/proto/com/google/protobuf/evil_names_proto2.proto
  81. 6
      java/kotlin/src/test/proto/com/google/protobuf/evil_names_proto3.proto
  82. 2
      java/lite/pom.xml
  83. 8
      java/lite/src/test/java/com/google/protobuf/LiteTest.java
  84. 4
      objectivec/Tests/unittest.proto
  85. 2
      php/BUILD.bazel
  86. 94
      php/ext/google/protobuf/php-upb.c
  87. 1520
      php/ext/google/protobuf/php-upb.h
  88. 3
      php/src/Google/Protobuf/Internal/Message.php
  89. 15
      php/tests/EncodeDecodeTest.php
  90. 8
      protobuf.bzl
  91. 9
      protobuf_deps.bzl
  92. 55
      protos/protos.h
  93. 53
      protos_generator/gen_messages.cc
  94. 79
      protos_generator/tests/test_generated.cc
  95. 13
      protos_generator/tests/test_model.proto
  96. 5
      python/build_targets.bzl
  97. 4
      python/google/protobuf/internal/descriptor_test.py
  98. 11
      python/google/protobuf/internal/enum_type_wrapper.py
  99. 8
      python/google/protobuf/internal/json_format_test.py
  100. 53
      python/google/protobuf/internal/message_test.py
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,10 +1,15 @@
matrix:
platform: ["debian10", "macos", "ubuntu2004", "windows"]
bazel: [6.x, 7.x]
tasks:
verify_targets:
name: "Verify build targets"
platform: ${{ platform }}
bazel: ${{ bazel }}
build_flags:
- '--host_cxxopt=-std=c++14'
- '--cxxopt=-std=c++14'
build_targets:
- '@protobuf//:protobuf'
- '@protobuf//:protobuf_lite'
@ -17,9 +22,14 @@ bcr_test_module:
matrix:
platform: ["debian10", "macos", "ubuntu2004", "windows"]
bazel: [6.x, 7.x]
tasks:
run_test_module:
name: "Run test module"
platform: ${{ platform }}
bazel: ${{ bazel }}
build_flags:
- '--host_cxxopt=-std=c++14'
- '--cxxopt=-std=c++14'
build_targets:
- "//..."

@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
branch: [main, 22.x, 23.x, 24.x, 25.x, 26.x]
branch: [main, 25.x, 27.x]
os: [{ name: Linux, value: ubuntu-latest}]
name: Test staleness ${{ matrix.os.name }} ${{ github.head_ref && 'PR' || matrix.branch }}
@ -26,7 +26,7 @@ jobs:
if: ${{ github.event.repository.full_name == 'protocolbuffers/protobuf' }}
steps:
- name: Checkout ${{ github.head_ref && 'PR' || matrix.branch }}
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout || github.head_ref || matrix.branch }}
@ -49,7 +49,7 @@ jobs:
# In branches where automatic updates work as post-submits, we don't want to run staleness
# tests along with user changes. Any stale files will be automatically fixed in a follow-up
# commit.
uses: protocolbuffers/protobuf-ci/bazel@v2
uses: protocolbuffers/protobuf-ci/bazel@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: staleness

@ -1,23 +1,54 @@
name: Bazel
name: Bazel Tests
# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [main]
pull_request:
branches: [main]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
workflow_call:
inputs:
safe-checkout:
required: true
description: "The SHA key for the commit we want to run over"
type: string
concurrency:
# Cancel previous actions from the same PR or branch except 'main' branch.
# See https://docs.github.com/en/actions/using-jobs/using-concurrency and https://docs.github.com/en/actions/learn-github-actions/contexts for more info.
group: concurrency-group::${{ github.workflow }}::${{ github.event.pull_request.number > 0 && format('pr-{0}', github.event.pull_request.number) || github.ref_name }}${{ github.ref_name == 'main' && format('::{0}', github.run_id) || ''}}
cancel-in-progress: ${{ github.ref_name != 'main' }}
permissions:
contents: read
jobs:
test:
uses: bazel-contrib/.github/.github/workflows/bazel.yaml@v6
with:
folders: '["examples"]'
examples:
strategy:
fail-fast: false
matrix:
runner: [ ubuntu, windows, macos ]
bazelversion: [ '7.1.1' ]
bzlmod: [true, false ]
include:
- runner: ubuntu
bazelversion: '6.4.0'
bzlmod: true
- runner: ubuntu
bazelversion: '6.4.0'
bzlmod: false
runs-on: ${{ matrix.runner }}-latest
name: Examples ${{ matrix.runner }} ${{ matrix.bazelversion }}${{ matrix.bzlmod && ' (bzlmod)' || '' }}
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Windows startup flags
if: runner.os == 'Windows'
working-directory: examples
shell: bash
run: echo "startup --output_user_root=C:/ --windows_enable_symlinks" >> .bazelrc
- name: Configure Bazel version
working-directory: examples
shell: bash
run: echo "${{ matrix.bazelversion }}" > .bazelversion
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: examples
version: ${{ matrix.bazelversion }}
bash: cd examples && bazel build //... $BAZEL_FLAGS --enable_bzlmod=${{ matrix.bzlmod }}

@ -43,11 +43,11 @@ jobs:
runs-on: ${{ matrix.config.runner || 'ubuntu-latest' }}
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: ${{ matrix.image }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -63,11 +63,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:${{ matrix.version }}-6.3.0-63dd26c0c7a808d92673a3e52e848189d4ab0f17
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -83,24 +83,24 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
submodules: recursive
- name: Cross compile protoc for ${{ matrix.arch }}
id: cross-compile
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v2
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:6.3.0-91a0ac83e968068672bc6001a4d474cfd9a50f1d
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
architecture: linux-${{ matrix.arch }}
- name: Setup sccache
uses: protocolbuffers/protobuf-ci/sccache@v2
uses: protocolbuffers/protobuf-ci/sccache@v3
with:
cache-prefix: linux-release-${{ matrix.arch }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:${{ matrix.arch }}-63dd26c0c7a808d92673a3e52e848189d4ab0f17
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -135,18 +135,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Setup sccache
uses: protocolbuffers/protobuf-ci/sccache@v2
uses: protocolbuffers/protobuf-ci/sccache@v3
with:
cache-prefix: linux-cmake
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/cmake:3.13.3-63dd26c0c7a808d92673a3e52e848189d4ab0f17
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -160,19 +160,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
submodules: recursive
- name: Setup sccache
uses: protocolbuffers/protobuf-ci/sccache@v2
uses: protocolbuffers/protobuf-ci/sccache@v3
with:
cache-prefix: linux-cmake-install
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/cmake:3.13.3-63dd26c0c7a808d92673a3e52e848189d4ab0f17
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -193,18 +193,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Setup sccache
uses: protocolbuffers/protobuf-ci/sccache@v2
uses: protocolbuffers/protobuf-ci/sccache@v3
with:
cache-prefix: linux-cmake-examples
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/cmake:3.13.3-63dd26c0c7a808d92673a3e52e848189d4ab0f17
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -233,19 +233,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
submodules: recursive
- name: Setup sccache
uses: protocolbuffers/protobuf-ci/sccache@v2
uses: protocolbuffers/protobuf-ci/sccache@v3
with:
cache-prefix: linux-cmake-gcc
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:12.2-6.3.0-63dd26c0c7a808d92673a3e52e848189d4ab0f17
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -264,19 +264,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
submodules: recursive
- name: Setup sccache
uses: protocolbuffers/protobuf-ci/sccache@v2
uses: protocolbuffers/protobuf-ci/sccache@v3
with:
cache-prefix: linux-cmake-submodules
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/cmake:3.13.3-63dd26c0c7a808d92673a3e52e848189d4ab0f17
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -289,19 +289,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
submodules: recursive
- name: Setup sccache
uses: protocolbuffers/protobuf-ci/sccache@v2
uses: protocolbuffers/protobuf-ci/sccache@v3
with:
cache-prefix: linux-cmake-32-bit
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/32bit@sha256:8275360dc5d676f3470872d79087901c0e4153453976bea908a92c82e8d209ea
platform: linux/386
@ -348,11 +348,11 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel@v2
uses: protocolbuffers/protobuf-ci/bazel@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel: ${{ matrix.bazel }}
@ -414,7 +414,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
submodules: recursive
@ -438,7 +438,7 @@ jobs:
shell: bash
- name: Setup sccache
uses: protocolbuffers/protobuf-ci/sccache@v2
uses: protocolbuffers/protobuf-ci/sccache@v3
with:
cache-prefix: ${{ matrix.cache-prefix }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -446,7 +446,7 @@ jobs:
# Install phase.
- name: Configure CMake for install
if: matrix.install-flags
uses: protocolbuffers/protobuf-ci/bash@v2
uses: protocolbuffers/protobuf-ci/bash@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
command: cmake . ${{ matrix.install-flags }} ${{ env.SCCACHE_CMAKE_FLAGS }} -Dprotobuf_ALLOW_CCACHE=ON
@ -468,7 +468,7 @@ jobs:
run: cmake --build . --target clean && rm CMakeCache.txt
- name: Configure CMake
uses: protocolbuffers/protobuf-ci/bash@v2
uses: protocolbuffers/protobuf-ci/bash@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
command: cmake . ${{ matrix.flags }} ${{ env.SCCACHE_CMAKE_FLAGS }} -Dprotobuf_ALLOW_CCACHE=ON

@ -17,13 +17,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
# TODO Run this with Bazel once codegen is handled properly.
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:3.1.415-6.0.100-66964dc8b07b6d1fc73a5cc14e59e84c1c534cea
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -36,10 +36,10 @@ jobs:
dotnet test -c Release -f net6.0 src/Google.Protobuf.Test/Google.Protobuf.Test.csproj"
- name: Clear bazel between docker instances
run: sudo rm -rf _build
run: sudo rm -rf _build .repository-cache
- name: Run conformance tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:3.1.415-6.0.100-66964dc8b07b6d1fc73a5cc14e59e84c1c534cea
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -51,7 +51,7 @@ jobs:
runs-on: windows-2019
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
@ -70,7 +70,7 @@ jobs:
shell: bash
- name: Run tests
uses: protocolbuffers/protobuf-ci/bash@v2
uses: protocolbuffers/protobuf-ci/bash@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
command: |
@ -82,14 +82,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Build protobuf C# tests under x86_64 docker image
# Tests are built "dotnet publish" because we want all the dependencies to the copied to the destination directory
# (we want to avoid references to ~/.nuget that won't be available in the subsequent docker run)
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: mcr.microsoft.com/dotnet/sdk:6.0.100-bullseye-slim
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -106,7 +106,7 @@ jobs:
# running under current user's UID and GID. To be able to do that, we need to provide a home directory for the user
# otherwise the UID would be homeless under the docker container and pip install wouldn't work. For simplicity,
# we just run map the user's home to a throwaway temporary directory
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: mcr.microsoft.com/dotnet/sdk:6.0.100-bullseye-slim-arm64v8
skip-staleness-check: true

@ -40,11 +40,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: ${{ matrix.image }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -57,11 +57,11 @@ jobs:
# runs-on: ubuntu-latest
# steps:
# - name: Checkout pending changes
# uses: protocolbuffers/protobuf-ci/checkout@v2
# uses: protocolbuffers/protobuf-ci/checkout@v3
# with:
# ref: ${{ inputs.safe-checkout }}
# - name: Run Linkage Monitor test
# uses: protocolbuffers/protobuf-ci/bazel-docker@v2
# uses: protocolbuffers/protobuf-ci/bazel-docker@v3
# with:
# image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:8-1fdbb997433cb22c1e49ef75ad374a8d6bb88702
# credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -75,12 +75,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Build protoc
id: build-protoc
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v2
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:6.3.0-91a0ac83e968068672bc6001a4d474cfd9a50f1d
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -94,7 +94,7 @@ jobs:
mvn -e -B -Dhttps.protocols=TLSv1.2 install -Dmaven.test.skip=true
working-directory: java
- name: Generate pom.xml files from the template
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:11-1fdbb997433cb22c1e49ef75ad374a8d6bb88702
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}

@ -34,18 +34,18 @@ jobs:
DEVELOPER_DIR: /Applications/Xcode_14.1.app/Contents/Developer
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Setup ccache
uses: protocolbuffers/protobuf-ci/ccache@v2
uses: protocolbuffers/protobuf-ci/ccache@v3
with:
cache-prefix: objectivec_${{ matrix.platform }}_${{ matrix.xc_config }}
support-modules: true
- name: Run tests
uses: protocolbuffers/protobuf-ci/bash@v2
uses: protocolbuffers/protobuf-ci/bash@v3
env:
CC: ${{ github.workspace }}/ci/clang_wrapper
CXX: ${{ github.workspace }}/ci/clang_wrapper++
@ -80,13 +80,13 @@ jobs:
runs-on: ${{ matrix.OS }}
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Xcode version
run: sudo xcode-select -switch /Applications/Xcode_${{ matrix.XCODE }}.app
- name: Pod lib lint
uses: protocolbuffers/protobuf-ci/bazel@v2
uses: protocolbuffers/protobuf-ci/bazel@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: cocoapods/${{ matrix.XCODE }}
@ -125,11 +125,11 @@ jobs:
runs-on: macos-12
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: bazel ${{ matrix.config.bazel_action }}
uses: protocolbuffers/protobuf-ci/bazel@v2
uses: protocolbuffers/protobuf-ci/bazel@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel: ${{ matrix.config.bazel_action }} ${{ matrix.config.flags }} ${{ matrix.bazel_targets }}

@ -44,16 +44,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Setup composer
uses: protocolbuffers/protobuf-ci/composer-setup@v2
uses: protocolbuffers/protobuf-ci/composer-setup@v3
with:
cache-prefix: php-${{ matrix.version-short }}
directory: php
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/php:${{ matrix.version }}-66964dc8b07b6d1fc73a5cc14e59e84c1c534cea
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -82,26 +82,26 @@ jobs:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/32bit@sha256:836f2cedcfe351d9a30055076630408e61994fc7d783e8333a99570968990eeb
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Cross compile protoc for i386
id: cross-compile
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v2
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:6.3.0-91a0ac83e968068672bc6001a4d474cfd9a50f1d
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
architecture: linux-i386
- name: Setup composer
uses: protocolbuffers/protobuf-ci/composer-setup@v2
uses: protocolbuffers/protobuf-ci/composer-setup@v3
with:
cache-prefix: php-${{ matrix.version }}
directory: php
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: ${{ env.image }}
platform: linux/386
@ -119,26 +119,26 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Cross compile protoc for aarch64
id: cross-compile
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v2
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:6.3.0-91a0ac83e968068672bc6001a4d474cfd9a50f1d
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
architecture: linux-aarch64
- name: Setup composer
uses: protocolbuffers/protobuf-ci/composer-setup@v2
uses: protocolbuffers/protobuf-ci/composer-setup@v3
with:
cache-prefix: php-8.1
directory: php
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/php-aarch64@sha256:77ff9fdec867bbfb290ee0b10d8b7a3e5e434155daa5ec93de7341c7592b858d
platform: linux/arm64
@ -161,7 +161,7 @@ jobs:
runs-on: macos-12
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
@ -180,13 +180,13 @@ jobs:
run: php --version | grep ${{ matrix.version }} || (echo "Invalid PHP version - $(php --version)" && exit 1)
- name: Setup composer
uses: protocolbuffers/protobuf-ci/composer-setup@v2
uses: protocolbuffers/protobuf-ci/composer-setup@v3
with:
cache-prefix: php-${{ matrix.version }}
directory: php
- name: Run tests
uses: protocolbuffers/protobuf-ci/bash@v2
uses: protocolbuffers/protobuf-ci/bash@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
command: |
@ -198,7 +198,7 @@ jobs:
popd
- name: Run conformance tests
uses: protocolbuffers/protobuf-ci/bazel@v2
uses: protocolbuffers/protobuf-ci/bazel@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: php_macos/${{ matrix.version }}

@ -17,12 +17,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Package extension
uses: protocolbuffers/protobuf-ci/bazel@v2
uses: protocolbuffers/protobuf-ci/bazel@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: php_ext/${{ matrix.version }}
@ -50,7 +50,7 @@ jobs:
name: protobuf-php-release
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/php-extension:${{ matrix.version }}-a48f26c08d9a803dd0177dda63563f6ea6f7b2d4
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}

@ -37,11 +37,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/python:{0}-63dd26c0c7a808d92673a3e52e848189d4ab0f17', matrix.version) }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -68,7 +68,7 @@ jobs:
runs-on: macos-12
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
@ -88,7 +88,7 @@ jobs:
source venv/bin/activate
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel@v2
uses: protocolbuffers/protobuf-ci/bazel@v3
env:
KOKORO_PYTHON_VERSION: ${{ matrix.version }}
with:

@ -34,11 +34,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:{0}-6.3.0-a6940b1421a71325ef4c7828ec72d404f56bbf30', matrix.ruby) }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -50,20 +50,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Cross compile protoc for i386
id: cross-compile
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v2
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:6.3.0-91a0ac83e968068672bc6001a4d474cfd9a50f1d
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
architecture: linux-i386
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: i386/ruby:3.0.2-buster
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -81,20 +81,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Cross compile protoc for aarch64
id: cross-compile
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v2
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:6.3.0-91a0ac83e968068672bc6001a4d474cfd9a50f1d
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
architecture: linux-aarch64
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v2
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: arm64v8/ruby:3.0.2-buster
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -128,7 +128,7 @@ jobs:
runs-on: macos-12
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
@ -141,7 +141,7 @@ jobs:
run: ruby --version | grep ${{ matrix.version }} || (echo "Invalid Ruby version - $(ruby --version)" && exit 1)
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel@v2
uses: protocolbuffers/protobuf-ci/bazel@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: ruby_macos/${{ matrix.version }}
@ -166,11 +166,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:${{ matrix.ruby }}-6.3.0-a6940b1421a71325ef4c7828ec72d404f56bbf30
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}

@ -52,6 +52,10 @@ on:
permissions:
contents: read
concurrency:
group: ${{ github.event_name }}-${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: ${{ contains(fromJSON('["pull_request", "pull_request_target", "workflow_dispatch"]'), github.event_name) }}
jobs:
check-tag:
name: Check for Safety
@ -105,6 +109,14 @@ jobs:
# Note: this pattern of passing the head sha is vulnerable to PWN requests for
# pull_request_target events. We carefully limit those workflows to require a
# human stamp before continuing.
bazel:
name: Bazel
needs: [check-tag]
uses: ./.github/workflows/test_bazel.yml
with:
safe-checkout: ${{ needs.check-tag.outputs.checkout-sha }}
secrets: inherit
cpp:
name: C++
needs: [check-tag]

@ -17,13 +17,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:7.1.1-75f2a85ece6526cc3d54087018c0f1097d78d42b"
image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:7.1.1-97f82260fd504923d8af642d567afb2d83a1959d"
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: rust_linux
bazel: >-

@ -31,11 +31,11 @@ jobs:
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:${{ matrix.config.bazel_version || '6.3.0' }}-75f2a85ece6526cc3d54087018c0f1097d78d42b
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -50,11 +50,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:12.2-6.3.0-63dd26c0c7a808d92673a3e52e848189d4ab0f17"
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -68,7 +68,7 @@ jobs:
runs-on: windows-2022
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0
@ -76,7 +76,7 @@ jobs:
cache: pip
cache-dependency-path: 'python/requirements.txt'
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel@v2
uses: protocolbuffers/protobuf-ci/bazel@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: "upb-bazel-windows"
@ -95,7 +95,7 @@ jobs:
runs-on: macos-12
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0
@ -103,7 +103,7 @@ jobs:
cache: pip
cache-dependency-path: 'python/requirements.txt'
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel@v2
uses: protocolbuffers/protobuf-ci/bazel@v3
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: "upb-bazel-macos"
@ -117,11 +117,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:6.3.0-91a0ac83e968068672bc6001a4d474cfd9a50f1d
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@ -138,11 +138,11 @@ jobs:
if: ${{ github.event_name != 'pull_request_target' }}
steps:
- name: Checkout pending changes
uses: protocolbuffers/protobuf-ci/checkout@v2
uses: protocolbuffers/protobuf-ci/checkout@v3
with:
ref: ${{ inputs.safe-checkout }}
- name: Build Wheels
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/release-containers/linux/apple@sha256:b3dc9b75d8e599b0e95ed245d89f44b5a4231112f975da89dd02006a484a58df
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}

@ -1,12 +1,12 @@
{
"checksum": "f93f5d1848bc00c6384273f9fb5273cc1b7fc0cb4dbc2afd776d2feb7b37f3ae",
"checksum": "8863e5b8f3da7cf4502f68bea0d455dec4834bf25ff070caaa58a8e1c5ea1a3d",
"crates": {
"aho-corasick 1.1.2": {
"name": "aho-corasick",
"version": "1.1.2",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/aho-corasick/1.1.2/download",
"url": "https://static.crates.io/crates/aho-corasick/1.1.2/download",
"sha256": "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
}
},
@ -53,7 +53,7 @@
"version": "1.1.0",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/autocfg/1.1.0/download",
"url": "https://static.crates.io/crates/autocfg/1.1.0/download",
"sha256": "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
}
},
@ -101,7 +101,7 @@
"deps": {
"common": [
{
"id": "googletest 0.10.0",
"id": "googletest 0.11.0",
"target": "googletest"
}
],
@ -121,13 +121,16 @@
},
"license": null
},
"googletest 0.10.0": {
"googletest 0.11.0": {
"name": "googletest",
"version": "0.10.0",
"version": "0.11.0",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/googletest/0.10.0/download",
"sha256": "09213705c85aa0e4b4fff44a3a826a556979a34a266df6bcda703a49c69fb61e"
"Git": {
"remote": "https://github.com/google/googletest-rust",
"commitish": {
"Rev": "471d4a2a8e8bc74f6d7d9c8eecb4d4e3157b2a9f"
},
"strip_prefix": "googletest"
}
},
"targets": [
@ -163,7 +166,7 @@
"proc_macro_deps": {
"common": [
{
"id": "googletest_macro 0.10.0",
"id": "googletest_macro 0.11.0",
"target": "googletest_macro"
},
{
@ -173,17 +176,20 @@
],
"selects": {}
},
"version": "0.10.0"
"version": "0.11.0"
},
"license": "Apache-2.0"
},
"googletest_macro 0.10.0": {
"googletest_macro 0.11.0": {
"name": "googletest_macro",
"version": "0.10.0",
"version": "0.11.0",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/googletest_macro/0.10.0/download",
"sha256": "005e4cb962c56efd249bdeeb4ac232b11e1c45a2e49793bba2b2982dcc3f2e9d"
"Git": {
"remote": "https://github.com/google/googletest-rust",
"commitish": {
"Rev": "471d4a2a8e8bc74f6d7d9c8eecb4d4e3157b2a9f"
},
"strip_prefix": "googletest_macro"
}
},
"targets": [
@ -209,14 +215,14 @@
"target": "quote"
},
{
"id": "syn 2.0.38",
"id": "syn 2.0.43",
"target": "syn"
}
],
"selects": {}
},
"edition": "2021",
"version": "0.10.0"
"version": "0.11.0"
},
"license": "Apache-2.0"
},
@ -225,7 +231,7 @@
"version": "2.6.4",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/memchr/2.6.4/download",
"url": "https://static.crates.io/crates/memchr/2.6.4/download",
"sha256": "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
}
},
@ -263,7 +269,7 @@
"version": "0.2.17",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/num-traits/0.2.17/download",
"url": "https://static.crates.io/crates/num-traits/0.2.17/download",
"sha256": "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
}
},
@ -332,7 +338,7 @@
"version": "1.0.14",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/paste/1.0.14/download",
"url": "https://static.crates.io/crates/paste/1.0.14/download",
"sha256": "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
}
},
@ -385,7 +391,7 @@
"version": "1.0.69",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/proc-macro2/1.0.69/download",
"url": "https://static.crates.io/crates/proc-macro2/1.0.69/download",
"sha256": "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
}
},
@ -448,7 +454,7 @@
"version": "1.0.33",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/quote/1.0.33/download",
"url": "https://static.crates.io/crates/quote/1.0.33/download",
"sha256": "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
}
},
@ -494,7 +500,7 @@
"version": "1.10.0",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/regex/1.10.0/download",
"url": "https://static.crates.io/crates/regex/1.10.0/download",
"sha256": "d119d7c7ca818f8a53c300863d4f87566aac09943aef5b355bb83969dae75d87"
}
},
@ -567,7 +573,7 @@
"version": "0.4.1",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/regex-automata/0.4.1/download",
"url": "https://static.crates.io/crates/regex-automata/0.4.1/download",
"sha256": "465c6fc0621e4abc4187a2bda0937bfd4f722c2730b29562e19689ea796c9a4b"
}
},
@ -641,7 +647,7 @@
"version": "0.8.1",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/regex-syntax/0.8.1/download",
"url": "https://static.crates.io/crates/regex-syntax/0.8.1/download",
"sha256": "56d84fdd47036b038fc80dd333d10b6aab10d5d31f4a366e20014def75328d33"
}
},
@ -686,7 +692,7 @@
"version": "1.0.14",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/rustversion/1.0.14/download",
"url": "https://static.crates.io/crates/rustversion/1.0.14/download",
"sha256": "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
}
},
@ -734,13 +740,13 @@
},
"license": "MIT OR Apache-2.0"
},
"syn 2.0.38": {
"syn 2.0.43": {
"name": "syn",
"version": "2.0.38",
"version": "2.0.43",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/syn/2.0.38/download",
"sha256": "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
"url": "https://static.crates.io/crates/syn/2.0.43/download",
"sha256": "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53"
}
},
"targets": [
@ -790,7 +796,7 @@
"selects": {}
},
"edition": "2021",
"version": "2.0.38"
"version": "2.0.43"
},
"license": "MIT OR Apache-2.0"
},
@ -799,7 +805,7 @@
"version": "1.0.12",
"repository": {
"Http": {
"url": "https://crates.io/api/v1/crates/unicode-ident/1.0.12/download",
"url": "https://static.crates.io/crates/unicode-ident/1.0.12/download",
"sha256": "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
}
},

14
Cargo.lock generated

@ -27,9 +27,8 @@ dependencies = [
[[package]]
name = "googletest"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09213705c85aa0e4b4fff44a3a826a556979a34a266df6bcda703a49c69fb61e"
version = "0.11.0"
source = "git+https://github.com/google/googletest-rust?rev=471d4a2a8e8bc74f6d7d9c8eecb4d4e3157b2a9f#471d4a2a8e8bc74f6d7d9c8eecb4d4e3157b2a9f"
dependencies = [
"googletest_macro",
"num-traits",
@ -39,9 +38,8 @@ dependencies = [
[[package]]
name = "googletest_macro"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "005e4cb962c56efd249bdeeb4ac232b11e1c45a2e49793bba2b2982dcc3f2e9d"
version = "0.11.0"
source = "git+https://github.com/google/googletest-rust?rev=471d4a2a8e8bc74f6d7d9c8eecb4d4e3157b2a9f#471d4a2a8e8bc74f6d7d9c8eecb4d4e3157b2a9f"
dependencies = [
"quote",
"syn",
@ -123,9 +121,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "syn"
version = "2.0.38"
version = "2.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53"
dependencies = [
"proc-macro2",
"quote",

@ -1,10 +1,9 @@
# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel
# https://github.com/protocolbuffers/protobuf/issues/14313
PROTOBUF_VERSION = "28.0-dev"
module(
name = "protobuf",
version = PROTOBUF_VERSION,
version = "28.0-dev", # Automatically updated on release
compatibility_level = 1,
repo_name = "com_google_protobuf",
)

@ -164,13 +164,6 @@ http_archive(
patch_cmds = ["find google -type f -name BUILD.bazel -delete"],
)
load("//python/dist:system_python.bzl", "system_python")
system_python(
name = "system_python",
minimum_python_version = "3.7",
)
load("@system_python//:pip.bzl", "pip_parse")
pip_parse(
@ -222,7 +215,8 @@ crates_repository(
lockfile = "//:Cargo.bazel.lock",
packages = {
"googletest": crate.spec(
version = ">0.0.0",
git = "https://github.com/google/googletest-rust",
rev = "471d4a2a8e8bc74f6d7d9c8eecb4d4e3157b2a9f",
),
"paste": crate.spec(
version = ">=1",
@ -232,3 +226,18 @@ crates_repository(
load("@crate_index//:defs.bzl", "crate_repositories")
crate_repositories()
# For testing runtime against old gencode from a previous major version.
http_archive(
name = "com_google_protobuf_v25.0",
strip_prefix = "protobuf-25.0",
url = "https://github.com/protocolbuffers/protobuf/releases/download/v25.0/protobuf-25.0.tar.gz",
)
# Needed as a dependency of @com_google_protobuf_v25.x, which was before
# utf8_range was merged in.
http_archive(
name = "utf8_range",
strip_prefix = "utf8_range-d863bc33e15cba6d873c878dcca9e6fe52b2f8cb",
url = "https://github.com/protocolbuffers/utf8_range/archive/d863bc33e15cba6d873c878dcca9e6fe52b2f8cb.zip",
)

@ -0,0 +1,17 @@
# Copyright (c) 2009-2021, Google LLC
# All rights reserved.
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd
"""Temporary alias to repository rule for using Python 3.x headers from the system."""
load(
"//python/dist:system_python.bzl",
_system_python = "system_python",
)
# TODO: Temporary alias. This is deprecated and to be removed in a future
# release. Users should now get system_python from protobuf_deps.bzl.
system_python = _system_python

@ -14,10 +14,24 @@ package(
)
create_compiler_config_setting(
name = "config_msvc",
name = "config_msvc_cl",
value = "msvc-cl",
)
# Caveat: clang-cl support in protobuf is only best-effort / untested for now.
create_compiler_config_setting(
name = "config_clang_cl",
value = "clang-cl",
)
selects.config_setting_group(
name = "config_msvc",
match_any = [
":config_clang_cl",
":config_msvc_cl",
],
)
config_setting(
name = "aarch64",
values = {"cpu": "linux-aarch_64"},

@ -1,2 +1,5 @@
import common.bazelrc
# Workaround for maximum path length issues
startup --output_user_root=C:/tmp --windows_enable_symlinks
common --enable_runfiles

@ -2,3 +2,4 @@ import common.bazelrc
build --cxxopt=-std=c++14 --host_cxxopt=-std=c++14
common --repo_env=BAZEL_NO_APPLE_CPP_TOOLCHAIN=1
common --xcode_version_config=@com_google_protobuf//.github:host_xcodes

@ -44,9 +44,12 @@ macro(_check_and_save_build_option OPTION VALUE)
endif()
set(${PACKAGE_FIND_NAME}_${OPTION} ${VALUE} PARENT_SCOPE)
endmacro()
_check_and_save_build_option(WITH_ZLIB @protobuf_WITH_ZLIB@)
_check_and_save_build_option(MSVC_STATIC_RUNTIME @protobuf_MSVC_STATIC_RUNTIME@)
_check_and_save_build_option(BUILD_SHARED_LIBS @protobuf_BUILD_SHARED_LIBS@)
if(PACKAGE_VERSION_COMPATIBLE)
_check_and_save_build_option(WITH_ZLIB @protobuf_WITH_ZLIB@)
_check_and_save_build_option(MSVC_STATIC_RUNTIME @protobuf_MSVC_STATIC_RUNTIME@)
_check_and_save_build_option(BUILD_SHARED_LIBS @protobuf_BUILD_SHARED_LIBS@)
endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if(CMAKE_SIZEOF_VOID_P AND "@CMAKE_SIZEOF_VOID_P@")

@ -0,0 +1,20 @@
# Simple build tests for compatibility of gencode from previous major versions
# with the current runtime.
#
# To add more test cases in Java, use java_runtime_conformance as below, and add
# the corresponding http_archive in the WORKSPACE file for the version.
load("//compatibility:runtime_conformance.bzl", "java_runtime_conformance")
# main gencode builds with main runtime as a proof of concept.
java_runtime_conformance(
name = "java_conformance_main",
gencode_version = "main",
)
# Generates a build_test named "conformance_v3.25.0"
java_runtime_conformance(
name = "java_conformance_v3.25.0",
gencode_version = "3.25.0",
tags = ["manual"],
)

@ -0,0 +1,53 @@
"""Provides a rule to generate a conformance test for a given version of the gencode."""
load("@bazel_skylib//rules:build_test.bzl", "build_test")
def java_runtime_conformance(name, gencode_version, tags = []):
"""Generates a conformance test for the given version of the runtime.
For example, runtime_conformance("3.19.4") will generate a build test named "conformance_v3.19.4"
that will fail if the runtime at that version fails to compile the unittest proto.
Args:
name: The name of the test.
gencode_version: The version of the runtime to test.
tags: Any tags to apply to the generated test.
"""
if gencode_version == "main":
protoc = "//:protoc"
else:
minor = gencode_version[gencode_version.find(".") + 1:]
protoc = Label("@com_google_protobuf_v%s//:protoc" % minor)
gencode = [
"v%s/protobuf_unittest/UnittestProto.java" % gencode_version,
"v%s/com/google/protobuf/test/UnittestImport.java" % gencode_version,
"v%s/com/google/protobuf/test/UnittestImportPublic.java" % gencode_version,
]
native.genrule(
name = "unittest_proto_gencode_v" + gencode_version,
srcs = [
"//src/google/protobuf:unittest_proto_srcs",
],
outs = gencode,
cmd = "$(location %s) " % protoc +
"$(locations //src/google/protobuf:unittest_proto_srcs) " +
" -Isrc/ --java_out=$(@D)/v%s" % gencode_version,
tools = [protoc],
)
conformance_name = "conformance_v" + gencode_version
conformance_lib_name = conformance_name + "_lib"
native.java_library(
name = conformance_lib_name,
srcs = gencode,
deps = ["//java/core"],
tags = tags,
)
build_test(
name = name,
targets = [":" + conformance_lib_name],
tags = tags,
)

@ -332,13 +332,14 @@ inline_sh_binary(
],
cmd = """
php -dextension=$(rootpath //php:extension) \\
-d include_path=conformance:src/google/protobuf \\
-d include_path=conformance:src/google/protobuf:editions/golden \\
$(rootpath conformance_php.php)
""",
visibility = ["//php:__subpackages__"],
deps = [
":conformance_php_proto",
"//:test_messages_proto3_php_proto",
"//editions:test_messages_proto3_editions_php_proto",
],
)

@ -65,7 +65,7 @@ ConformanceResponse doTest(ConformanceRequest request) {
switch (request.requestedOutputFormat) {
case WireFormat.PROTOBUF:
try {
response.protobufPayload = pb.GeneratedMessage.toBuffer(testMessage);
response.protobufPayload = pb.GeneratedMessage.toBinary(testMessage);
} catch (e) {
response.serializeError = '$e';
}
@ -86,7 +86,7 @@ Future<bool> doTestIo() async {
}
final request = ConformanceRequest.fromBuffer(serializedMsg);
final response = doTest(request);
final serializedOutput = pb.GeneratedMessage.toBuffer(response);
final serializedOutput = pb.GeneratedMessage.toBinary(response);
writeLittleEndianIntToStdout(serializedOutput.length);
stdout.add(serializedOutput);
await stdout.flush();

@ -1,80 +1,134 @@
<?php
require_once("Conformance/WireFormat.php");
require_once("Conformance/ConformanceResponse.php");
require_once("Conformance/ConformanceRequest.php");
require_once("Conformance/FailureSet.php");
require_once("Conformance/JspbEncodingConfig.php");
require_once("Conformance/TestCategory.php");
require_once("Protobuf_test_messages/Proto3/ForeignMessage.php");
require_once("Protobuf_test_messages/Proto3/ForeignEnum.php");
require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3.php");
require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3/AliasedEnum.php");
require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3/NestedMessage.php");
require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3/NestedEnum.php");
require_once("GPBMetadata/Conformance.php");
require_once("GPBMetadata/TestMessagesProto3.php");
use \Conformance\TestCategory;
use \Conformance\WireFormat;
if (!ini_get("date.timezone")) {
ini_set("date.timezone", "UTC");
require_once('Conformance/WireFormat.php');
require_once('Conformance/ConformanceResponse.php');
require_once('Conformance/ConformanceRequest.php');
require_once('Conformance/FailureSet.php');
require_once('Conformance/JspbEncodingConfig.php');
require_once('Conformance/TestCategory.php');
require_once('Protobuf_test_messages/Proto3/ForeignMessage.php');
require_once('Protobuf_test_messages/Proto3/ForeignEnum.php');
require_once('Protobuf_test_messages/Proto3/TestAllTypesProto3.php');
require_once('Protobuf_test_messages/Proto3/TestAllTypesProto3/AliasedEnum.php');
require_once('Protobuf_test_messages/Proto3/TestAllTypesProto3/NestedMessage.php');
require_once('Protobuf_test_messages/Proto3/TestAllTypesProto3/NestedEnum.php');
require_once('Protobuf_test_messages/Editions/Proto3/EnumOnlyProto3/PBBool.php');
require_once('Protobuf_test_messages/Editions/Proto3/EnumOnlyProto3.php');
require_once('Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3/NestedMessage.php');
require_once('Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3/NestedEnum.php');
require_once('Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3/AliasedEnum.php');
require_once('Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3.php');
require_once('Protobuf_test_messages/Editions/Proto3/NullHypothesisProto3.php');
require_once('Protobuf_test_messages/Editions/Proto3/ForeignEnum.php');
require_once('Protobuf_test_messages/Editions/Proto3/ForeignMessage.php');
require_once('GPBMetadata/Conformance.php');
require_once('GPBMetadata/TestMessagesProto3.php');
require_once('GPBMetadata/TestMessagesProto3Editions.php');
use Conformance\ConformanceRequest;
use Conformance\ConformanceResponse;
use Conformance\TestCategory;
use Conformance\WireFormat;
use Protobuf_test_messages\Proto3\TestAllTypesProto3;
use Protobuf_test_messages\Editions\Proto3\TestAllTypesProto3 as TestAllTypesProto3Editions;
if (!ini_get('date.timezone')) {
ini_set('date.timezone', 'UTC');
}
$test_count = 0;
function doTest($request)
{
$test_message = new \Protobuf_test_messages\Proto3\TestAllTypesProto3();
$response = new \Conformance\ConformanceResponse();
if ($request->getPayload() == "protobuf_payload") {
if ($request->getMessageType() == "conformance.FailureSet") {
$response->setProtobufPayload("");
return $response;
} elseif ($request->getMessageType() == "protobuf_test_messages.proto3.TestAllTypesProto3") {
try {
$test_message->mergeFromString($request->getProtobufPayload());
} catch (Exception $e) {
$response->setParseError($e->getMessage());
return $response;
}
} elseif ($request->getMessageType() == "protobuf_test_messages.proto2.TestAllTypesProto2") {
$response->setSkipped("PHP doesn't support proto2");
return $response;
} else {
trigger_error("Protobuf request doesn't have specific payload type", E_USER_ERROR);
}
} elseif ($request->getPayload() == "json_payload") {
$ignore_json_unknown =
($request->getTestCategory() ==
TestCategory::JSON_IGNORE_UNKNOWN_PARSING_TEST);
try {
$test_message->mergeFromJsonString($request->getJsonPayload(),
$ignore_json_unknown);
} catch (Exception $e) {
$response->setParseError($e->getMessage());
return $response;
}
} elseif ($request->getPayload() == "text_payload") {
$response->setSkipped("PHP doesn't support text format yet");
return $response;
} else {
trigger_error("Request didn't have payload.", E_USER_ERROR);
$response = new ConformanceResponse();
switch ($request->getPayload()) {
case 'protobuf_payload':
switch ($request->getMessageType()) {
case 'protobuf_test_messages.proto3.TestAllTypesProto3':
$test_message = new TestAllTypesProto3();
break;
case 'protobuf_test_messages.editions.proto3.TestAllTypesProto3':
$test_message = new TestAllTypesProto3Editions();
break;
case 'conformance.FailureSet':
$response->setProtobufPayload('');
return $response;
case 'protobuf_test_messages.proto2.TestAllTypesProto2':
case 'protobuf_test_messages.editions.proto2.TestAllTypesProto2':
$response->setSkipped('PHP doesn\'t support proto2');
return $response;
case 'protobuf_test_messages.editions.TestAllTypesEdition2023':
$response->setSkipped('PHP doesn\'t support editions-specific features yet');
return $response;
case '':
trigger_error(
'Protobuf request doesn\'t have specific payload type',
E_USER_ERROR
);
default:
trigger_error(sprintf(
'Protobuf request doesn\'t support %s message type',
$request->getMessageType(),
), E_USER_ERROR);
}
try {
$test_message->mergeFromString($request->getProtobufPayload());
} catch (Exception $e) {
$response->setParseError($e->getMessage());
return $response;
}
break;
case 'json_payload':
switch ($request->getMessageType()) {
case 'protobuf_test_messages.editions.proto3.TestAllTypesProto3':
$test_message = new TestAllTypesProto3Editions();
break;
case 'protobuf_test_messages.editions.proto2.TestAllTypesProto2':
$response->setSkipped('PHP doesn\'t support proto2');
return $response;
default:
$test_message = new TestAllTypesProto3();
}
$ignore_json_unknown =
($request->getTestCategory() == TestCategory::JSON_IGNORE_UNKNOWN_PARSING_TEST);
try {
$test_message->mergeFromJsonString(
$request->getJsonPayload(),
$ignore_json_unknown
);
} catch (Exception $e) {
$response->setParseError($e->getMessage());
return $response;
}
break;
case 'text_payload':
$response->setSkipped('PHP doesn\'t support text format yet');
return $response;
default:
trigger_error('Request didn\'t have payload.', E_USER_ERROR);
}
if ($request->getRequestedOutputFormat() == WireFormat::UNSPECIFIED) {
trigger_error("Unspecified output format.", E_USER_ERROR);
} elseif ($request->getRequestedOutputFormat() == WireFormat::PROTOBUF) {
$response->setProtobufPayload($test_message->serializeToString());
} elseif ($request->getRequestedOutputFormat() == WireFormat::JSON) {
try {
$response->setJsonPayload($test_message->serializeToJsonString());
} catch (Exception $e) {
$response->setSerializeError($e->getMessage());
return $response;
}
switch ($request->getRequestedOutputFormat()) {
case WireFormat::TEXT_FORMAT:
$response->setSkipped('PHP doesn\'t support text format yet');
return $response;
case WireFormat::UNSPECIFIED:
trigger_error('Unspecified output format.', E_USER_ERROR);
case WireFormat::PROTOBUF:
$response->setProtobufPayload($test_message->serializeToString());
break;
case WireFormat::JSON:
try {
$response->setJsonPayload($test_message->serializeToJsonString());
} catch (Exception $e) {
$response->setSerializeError($e->getMessage());
return $response;
}
}
return $response;
@ -84,25 +138,25 @@ function doTestIO()
{
$length_bytes = fread(STDIN, 4);
if (strlen($length_bytes) == 0) {
return false; # EOF
return false; # EOF
} elseif (strlen($length_bytes) != 4) {
fwrite(STDERR, "I/O error\n");
return false;
fwrite(STDERR, "I/O error\n");
return false;
}
$length = unpack("V", $length_bytes)[1];
$length = unpack('V', $length_bytes)[1];
$serialized_request = fread(STDIN, $length);
if (strlen($serialized_request) != $length) {
trigger_error("I/O error", E_USER_ERROR);
trigger_error('I/O error', E_USER_ERROR);
}
$request = new \Conformance\ConformanceRequest();
$request = new ConformanceRequest();
$request->mergeFromString($serialized_request);
$response = doTest($request);
$serialized_response = $response->serializeToString();
fwrite(STDOUT, pack("V", strlen($serialized_response)));
fwrite(STDOUT, pack('V', strlen($serialized_response)));
fwrite(STDOUT, $serialized_response);
$GLOBALS['test_count'] += 1;
@ -111,10 +165,10 @@ function doTestIO()
}
while(true){
if (!doTestIO()) {
fprintf(STDERR,
"conformance_php: received EOF from test runner " .
"after %d tests, exiting\n", $test_count);
exit;
}
if (!doTestIO()) {
fprintf(STDERR,
'conformance_php: received EOF from test runner ' .
"after %d tests, exiting\n", $test_count);
exit;
}
}

@ -1,3 +1,10 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2024 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
edition = "2023";
package protobuf_test_messages.editions;

@ -9,6 +9,7 @@
#include <cstddef>
#include <string>
#include <utility>
#include <vector>
#include "absl/log/absl_log.h"
@ -321,6 +322,44 @@ void TextFormatConformanceTestSuiteImpl<MessageType>::RunAllTests() {
"optional_int64: -9223372036854775808");
RunValidTextFormatTest("Uint64FieldMaxValue", REQUIRED,
"optional_uint64: 18446744073709551615");
// Integer fields - Hex
RunValidTextFormatTestWithExpected("Int32FieldMaxValueHex", REQUIRED,
"optional_int32: 0x7FFFFFFF",
"optional_int32: 2147483647");
RunValidTextFormatTestWithExpected("Int32FieldMinValueHex", REQUIRED,
"optional_int32: -0x80000000",
"optional_int32: -2147483648");
RunValidTextFormatTestWithExpected("Uint32FieldMaxValueHex", REQUIRED,
"optional_uint32: 0xFFFFFFFF",
"optional_uint32: 4294967295");
RunValidTextFormatTestWithExpected("Int64FieldMaxValueHex", REQUIRED,
"optional_int64: 0x7FFFFFFFFFFFFFFF",
"optional_int64: 9223372036854775807");
RunValidTextFormatTestWithExpected("Int64FieldMinValueHex", REQUIRED,
"optional_int64: -0x8000000000000000",
"optional_int64: -9223372036854775808");
RunValidTextFormatTestWithExpected("Uint64FieldMaxValueHex", REQUIRED,
"optional_uint64: 0xFFFFFFFFFFFFFFFF",
"optional_uint64: 18446744073709551615");
// Integer fields - Octal
RunValidTextFormatTestWithExpected("Int32FieldMaxValueOctal", REQUIRED,
"optional_int32: 017777777777",
"optional_int32: 2147483647");
RunValidTextFormatTestWithExpected("Int32FieldMinValueOctal", REQUIRED,
"optional_int32: -020000000000",
"optional_int32: -2147483648");
RunValidTextFormatTestWithExpected("Uint32FieldMaxValueOctal", REQUIRED,
"optional_uint32: 037777777777",
"optional_uint32: 4294967295");
RunValidTextFormatTestWithExpected("Int64FieldMaxValueOctal", REQUIRED,
"optional_int64: 0777777777777777777777",
"optional_int64: 9223372036854775807");
RunValidTextFormatTestWithExpected("Int64FieldMinValueOctal", REQUIRED,
"optional_int64: -01000000000000000000000",
"optional_int64: -9223372036854775808");
RunValidTextFormatTestWithExpected("Uint64FieldMaxValueOctal", REQUIRED,
"optional_uint64: 01777777777777777777777",
"optional_uint64: 18446744073709551615");
// Parsers reject out-of-bound integer values.
ExpectParseFailure("Int32FieldTooLarge", REQUIRED,
@ -335,30 +374,145 @@ void TextFormatConformanceTestSuiteImpl<MessageType>::RunAllTests() {
"optional_int64: -9223372036854775809");
ExpectParseFailure("Uint64FieldTooLarge", REQUIRED,
"optional_uint64: 18446744073709551616");
// Parsers reject out-of-bound integer values - Hex
ExpectParseFailure("Int32FieldTooLargeHex", REQUIRED,
"optional_int32: 0x80000000");
ExpectParseFailure("Int32FieldTooSmallHex", REQUIRED,
"optional_int32: -0x80000001");
ExpectParseFailure("Uint32FieldTooLargeHex", REQUIRED,
"optional_uint32: 0x100000000");
ExpectParseFailure("Int64FieldTooLargeHex", REQUIRED,
"optional_int64: 0x8000000000000000");
ExpectParseFailure("Int64FieldTooSmallHex", REQUIRED,
"optional_int64: -0x8000000000000001");
ExpectParseFailure("Uint64FieldTooLargeHex", REQUIRED,
"optional_uint64: 0x10000000000000000");
// Parsers reject out-of-bound integer values - Octal
ExpectParseFailure("Int32FieldTooLargeOctal", REQUIRED,
"optional_int32: 020000000000");
ExpectParseFailure("Int32FieldTooSmallOctal", REQUIRED,
"optional_int32: -020000000001");
ExpectParseFailure("Uint32FieldTooLargeOctal", REQUIRED,
"optional_uint32: 040000000000");
ExpectParseFailure("Int64FieldTooLargeOctal", REQUIRED,
"optional_int64: 01000000000000000000000");
ExpectParseFailure("Int64FieldTooSmallOctal", REQUIRED,
"optional_int64: -01000000000000000000001");
ExpectParseFailure("Uint64FieldTooLargeOctal", REQUIRED,
"optional_uint64: 02000000000000000000000");
// Floating point fields
RunValidTextFormatTest("FloatField", REQUIRED, "optional_float: 3.192837");
RunValidTextFormatTest("FloatFieldWithVeryPreciseNumber", REQUIRED,
"optional_float: 3.123456789123456789");
RunValidTextFormatTest("FloatFieldMaxValue", REQUIRED,
"optional_float: 3.4028235e+38");
RunValidTextFormatTest("FloatFieldMinValue", REQUIRED,
"optional_float: 1.17549e-38");
RunValidTextFormatTest("FloatFieldNaNValue", REQUIRED, "optional_float: NaN");
RunValidTextFormatTest("FloatFieldPosInfValue", REQUIRED,
"optional_float: inf");
RunValidTextFormatTest("FloatFieldNegInfValue", REQUIRED,
"optional_float: -inf");
RunValidTextFormatTest("FloatFieldWithInt32Max", REQUIRED,
"optional_float: 4294967296");
RunValidTextFormatTest("FloatFieldLargerThanInt64", REQUIRED,
"optional_float: 9223372036854775808");
RunValidTextFormatTest("FloatFieldTooLarge", REQUIRED,
"optional_float: 3.4028235e+39");
RunValidTextFormatTest("FloatFieldTooSmall", REQUIRED,
"optional_float: 1.17549e-39");
RunValidTextFormatTest("FloatFieldLargerThanUint64", REQUIRED,
"optional_float: 18446744073709551616");
for (const auto& suffix : std::vector<std::string>{"", "f", "F"}) {
const std::string name_suffix =
suffix.empty() ? "" : absl::StrCat("_", suffix);
RunValidTextFormatTest(absl::StrCat("FloatField", name_suffix), REQUIRED,
absl::StrCat("optional_float: 3.192837", suffix));
RunValidTextFormatTestWithExpected(
absl::StrCat("FloatFieldZero", name_suffix), REQUIRED,
absl::StrCat("optional_float: 0", suffix),
"" /* implicit presence, so zero means unset*/);
RunValidTextFormatTest(absl::StrCat("FloatFieldNegative", name_suffix),
REQUIRED,
absl::StrCat("optional_float: -3.192837", suffix));
RunValidTextFormatTest(
absl::StrCat("FloatFieldWithVeryPreciseNumber", name_suffix), REQUIRED,
absl::StrCat("optional_float: 3.123456789123456789", suffix));
RunValidTextFormatTest(
absl::StrCat("FloatFieldMaxValue", name_suffix), REQUIRED,
absl::StrCat("optional_float: 3.4028235e+38", suffix));
RunValidTextFormatTest(absl::StrCat("FloatFieldMinValue", name_suffix),
REQUIRED,
absl::StrCat("optional_float: 1.17549e-38", suffix));
RunValidTextFormatTest(absl::StrCat("FloatFieldWithInt32Max", name_suffix),
REQUIRED,
absl::StrCat("optional_float: 4294967296", suffix));
RunValidTextFormatTest(
absl::StrCat("FloatFieldLargerThanInt64", name_suffix), REQUIRED,
absl::StrCat("optional_float: 9223372036854775808", suffix));
RunValidTextFormatTest(
absl::StrCat("FloatFieldTooLarge", name_suffix), REQUIRED,
absl::StrCat("optional_float: 3.4028235e+39", suffix));
RunValidTextFormatTest(absl::StrCat("FloatFieldTooSmall", name_suffix),
REQUIRED,
absl::StrCat("optional_float: 1.17549e-39", suffix));
RunValidTextFormatTest(
absl::StrCat("FloatFieldLargerThanUint64", name_suffix), REQUIRED,
absl::StrCat("optional_float: 18446744073709551616", suffix));
// https://protobuf.dev/reference/protobuf/textformat-spec/#literals says
// "-0" is a valid float literal. -0 should be considered not the same as 0
// when considering implicit presence, and so should round trip.
RunValidTextFormatTest(absl::StrCat("FloatFieldNegativeZero", name_suffix),
REQUIRED,
absl::StrCat("optional_float: -0", suffix));
// https://protobuf.dev/reference/protobuf/textformat-spec/#literals says
// ".123", "-.123", ".123e2" are a valid float literal.
RunValidTextFormatTest(absl::StrCat("FloatFieldNoLeadingZero", name_suffix),
REQUIRED,
absl::StrCat("optional_float: .123", suffix));
RunValidTextFormatTest(
absl::StrCat("FloatFieldNegativeNoLeadingZero", name_suffix), REQUIRED,
absl::StrCat("optional_float: -.123", suffix));
RunValidTextFormatTest(
absl::StrCat("FloatFieldNoLeadingZeroWithExponent", name_suffix),
REQUIRED, absl::StrCat("optional_float: .123e2", suffix));
}
// https://protobuf.dev/reference/protobuf/textformat-spec/#value say case
// doesn't matter for special values, test a few
for (const auto& value : std::vector<std::string>{"nan", "NaN", "nAn"}) {
RunValidTextFormatTest(absl::StrCat("FloatFieldValue_", value), REQUIRED,
absl::StrCat("optional_float: ", value));
}
for (const auto& value : std::vector<std::string>{
"inf", "infinity", "INF", "INFINITY", "iNF", "inFINITY"}) {
RunValidTextFormatTest(absl::StrCat("FloatFieldValue_Pos", value), REQUIRED,
absl::StrCat("optional_float: ", value));
RunValidTextFormatTest(absl::StrCat("FloatFieldValue_Neg", value), REQUIRED,
absl::StrCat("optional_float: -", value));
}
// https://protobuf.dev/reference/protobuf/textformat-spec/#numeric and
// https://protobuf.dev/reference/protobuf/textformat-spec/#value says
// hex or octal float literals are invalid.
ExpectParseFailure("FloatFieldNoHex", REQUIRED, "optional_float: 0x1");
ExpectParseFailure("FloatFieldNoNegativeHex", REQUIRED,
"optional_float: -0x1");
ExpectParseFailure("FloatFieldNoOctal", REQUIRED, "optional_float: 012");
ExpectParseFailure("FloatFieldNoNegativeOctal", REQUIRED,
"optional_float: -012");
// https://protobuf.dev/reference/protobuf/textformat-spec/#value says
// overflows are mapped to infinity/-infinity.
RunValidTextFormatTestWithExpected("FloatFieldOverflowInfinity", REQUIRED,
"optional_float: 1e50",
"optional_float: inf");
RunValidTextFormatTestWithExpected("FloatFieldOverflowNegativeInfinity",
REQUIRED, "optional_float: -1e50",
"optional_float: -inf");
RunValidTextFormatTestWithExpected("DoubleFieldOverflowInfinity", REQUIRED,
"optional_double: 1e9999",
"optional_double: inf");
RunValidTextFormatTestWithExpected("DoubleFieldOverflowNegativeInfinity",
REQUIRED, "optional_double: -1e9999",
"optional_double: -inf");
// Exponent is one more than uint64 max.
RunValidTextFormatTestWithExpected(
"FloatFieldOverflowInfinityHugeExponent", REQUIRED,
"optional_float: 1e18446744073709551616", "optional_float: inf");
RunValidTextFormatTestWithExpected(
"DoubleFieldOverflowInfinityHugeExponent", REQUIRED,
"optional_double: 1e18446744073709551616", "optional_double: inf");
RunValidTextFormatTestWithExpected(
"DoubleFieldLargeNegativeExponentParsesAsZero", REQUIRED,
"optional_double: 1e-18446744073709551616", "");
RunValidTextFormatTestWithExpected(
"NegDoubleFieldLargeNegativeExponentParsesAsNegZero", REQUIRED,
"optional_double: -1e-18446744073709551616", "optional_double: -0");
RunValidTextFormatTestWithExpected(
"FloatFieldLargeNegativeExponentParsesAsZero", REQUIRED,
"optional_float: 1e-50", "");
RunValidTextFormatTestWithExpected(
"NegFloatFieldLargeNegativeExponentParsesAsNegZero", REQUIRED,
"optional_float: -1e-50", "optional_float: -0");
// String literals x {Strings, Bytes}
for (const auto& field_type : std::vector<std::string>{"String", "Bytes"}) {
@ -438,6 +592,95 @@ void TextFormatConformanceTestSuiteImpl<MessageType>::RunAllTests() {
absl::StrCat(field_name, ": '\\xc0'"));
}
// Separators
for (const auto& test_case : std::vector<std::pair<std::string, std::string>>{
{"string", "\"abc\""},
{"bytes", "\"abc\""},
{"int32", "123"},
{"bool", "true"},
{"double", "1.23"},
{"fixed32", "0x123"},
}) {
// Optional Field Separators
for (const auto& field_type :
std::vector<std::string>{"Single", "Repeated"}) {
std::string field_name, field_value;
if (field_type == "Single") {
field_name = absl::StrCat("optional_", test_case.first);
field_value = test_case.second;
} else {
field_name = absl::StrCat("repeated_", test_case.first);
field_value = absl::StrCat("[", test_case.second, "]");
}
RunValidTextFormatTest(absl::StrCat("FieldSeparatorCommaTopLevel",
field_type, "_", test_case.first),
REQUIRED,
absl::StrCat(field_name, ": ", field_value, ","));
RunValidTextFormatTest(absl::StrCat("FieldSeparatorSemiTopLevelSingle",
field_type, "_", test_case.first),
REQUIRED,
absl::StrCat(field_name, ": ", field_value, ";"));
ExpectParseFailure(
absl::StrCat("FieldSeparatorCommaTopLevelDuplicatesFails", field_type,
"_", test_case.first),
REQUIRED, absl::StrCat(field_name, ": ", field_value, ",,"));
ExpectParseFailure(
absl::StrCat("FieldSeparatorSemiTopLevelDuplicateFails", field_type,
"_", test_case.first),
REQUIRED, absl::StrCat(field_name, ": ", field_value, ";;"));
}
// Required List Separators
RunValidTextFormatTest(
absl::StrCat("ListSeparator_", test_case.first), REQUIRED,
absl::StrCat("repeated_", test_case.first, ": [", test_case.second, ",",
test_case.second, "]"));
ExpectParseFailure(
absl::StrCat("ListSeparatorSemiFails_", test_case.first), REQUIRED,
absl::StrCat("repeated_", test_case.first, ": [", test_case.second, ";",
test_case.second, "]"));
// For string and bytes, if we skip the separator, the parser will treat
// the two values as a single value.
if (test_case.first == "string" || test_case.first == "bytes") {
RunValidTextFormatTest(
absl::StrCat("ListSeparatorMissingIsOneValue_", test_case.first),
REQUIRED,
absl::StrCat("repeated_", test_case.first, ": [", test_case.second,
" ", test_case.second, "]"));
} else {
ExpectParseFailure(
absl::StrCat("ListSeparatorMissingFails_", test_case.first), REQUIRED,
absl::StrCat("repeated_", test_case.first, ": [", test_case.second,
" ", test_case.second, "]"));
}
ExpectParseFailure(
absl::StrCat("ListSeparatorDuplicateFails_", test_case.first), REQUIRED,
absl::StrCat("repeated_", test_case.first, ": [", test_case.second,
",,", test_case.second, "]"));
ExpectParseFailure(
absl::StrCat("ListSeparatorSingleTrailingFails_", test_case.first),
REQUIRED,
absl::StrCat("repeated_", test_case.first, ": [", test_case.second,
",]"));
ExpectParseFailure(
absl::StrCat("ListSeparatorTwoValuesTrailingFails_", test_case.first),
REQUIRED,
absl::StrCat("repeated_", test_case.first, ": [", test_case.second, ",",
test_case.second, ",]"));
}
// The test message don't really have all types nested, so just check one
// data type for the nested field separator support
RunValidTextFormatTest("FieldSeparatorCommaNested", REQUIRED,
"optional_nested_message: { a: 123, }");
RunValidTextFormatTest("FieldSeparatorSemiNested", REQUIRED,
"optional_nested_message: { a: 123; }");
ExpectParseFailure("FieldSeparatorCommaNestedDuplicates", REQUIRED,
"optional_nested_message: { a: 123,, }");
ExpectParseFailure("FieldSeparatorSemiNestedDuplicates", REQUIRED,
"optional_nested_message: { a: 123;; }");
// Unknown Fields
UnknownToTestAllTypes message;
// Unable to print unknown Fixed32/Fixed64 fields as if they are known.

@ -1,17 +1,20 @@
Recommended.Proto3.ProtobufInput.GroupUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.MessageUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
Required.Proto3.TextFormatInput.AnyField.ProtobufOutput
Required.Proto3.TextFormatInput.AnyField.TextFormatOutput
Recommended.Editions_Proto3.ProtobufInput.GroupUnknownFields_Drop.TextFormatOutput
Recommended.Editions_Proto3.ProtobufInput.MessageUnknownFields_Drop.TextFormatOutput
Recommended.Editions_Proto3.ProtobufInput.RepeatedUnknownFields_Drop.TextFormatOutput
Recommended.Editions_Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.GroupUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.MessageUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.AnyField.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.AnyField.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoNegativeOctal
Required.Editions_Proto3.TextFormatInput.FloatFieldNoOctal
Required.Editions_Proto3.TextFormatInput.StringFieldBadUTF8Hex
Required.Editions_Proto3.TextFormatInput.StringFieldBadUTF8Octal
Required.Proto3.TextFormatInput.AnyField.ProtobufOutput
Required.Proto3.TextFormatInput.AnyField.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNoNegativeOctal
Required.Proto3.TextFormatInput.FloatFieldNoOctal
Required.Proto3.TextFormatInput.StringFieldBadUTF8Hex
Required.Proto3.TextFormatInput.StringFieldBadUTF8Octal
Required.Editions_Proto3.TextFormatInput.StringFieldBadUTF8Hex
Required.Editions_Proto3.TextFormatInput.StringFieldBadUTF8Octal

@ -1,8 +0,0 @@
Recommended.Proto3.ProtobufInput.GroupUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.GroupUnknownFields_Print.TextFormatOutput
Recommended.Proto3.ProtobufInput.MessageUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.MessageUnknownFields_Print.TextFormatOutput
Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Print.TextFormatOutput
Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Print.TextFormatOutput

@ -1,15 +1,99 @@
# This is the list of text format conformance tests that are known to fail right
# now.
# TODO: These should be fixed.
Required.Proto3.TextFormatInput.FloatFieldMaxValue.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldMaxValue.TextFormatOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.TextFormatOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatField_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatField_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldLargerThanInt64_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldLargerThanInt64_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldLargerThanUint64_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldLargerThanUint64_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMaxValue_f.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMaxValue_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMaxValue_f.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMaxValue_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMaxValue.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMaxValue.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMinValue_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMinValue_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegative_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegative_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeNoLeadingZero_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeNoLeadingZero_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoLeadingZero_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoLeadingZero_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoLeadingZeroWithExponent_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoLeadingZeroWithExponent_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoNegativeOctal
Required.Editions_Proto3.TextFormatInput.FloatFieldNoOctal
Required.Editions_Proto3.TextFormatInput.FloatFieldTooLarge_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldTooLarge_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldTooSmall_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldTooSmall_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldWithInt32Max_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldWithInt32Max_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldWithVeryPreciseNumber_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldWithVeryPreciseNumber_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldZero_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldZero_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.StringLiteralBasicEscapesString.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.StringLiteralBasicEscapesString.TextFormatOutput
Required.Proto3.TextFormatInput.FloatField_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatField_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanInt64_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanInt64_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanUint64_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanUint64_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldMaxValue_f.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldMaxValue_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldMaxValue_f.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldMaxValue_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldMaxValue.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldMaxValue.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldMinValue_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldMinValue_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNegative_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNegative_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeNoLeadingZero_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeNoLeadingZero_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNoLeadingZero_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNoLeadingZero_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNoLeadingZeroWithExponent_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNoLeadingZeroWithExponent_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNoNegativeOctal
Required.Proto3.TextFormatInput.FloatFieldNoOctal
Required.Proto3.TextFormatInput.FloatFieldTooLarge_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldTooLarge_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldTooSmall_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldTooSmall_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldWithInt32Max_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldWithInt32Max_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldWithVeryPreciseNumber_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldWithVeryPreciseNumber_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldZero_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldZero_F.TextFormatOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.TextFormatOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeZero.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeZero.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeZero_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeZero_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeZero_f.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeZero_f.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.NegDoubleFieldLargeNegativeExponentParsesAsNegZero.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.NegDoubleFieldLargeNegativeExponentParsesAsNegZero.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.NegFloatFieldLargeNegativeExponentParsesAsNegZero.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.NegFloatFieldLargeNegativeExponentParsesAsNegZero.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeZero.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeZero.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeZero_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeZero_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeZero_f.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeZero_f.TextFormatOutput
Required.Proto3.TextFormatInput.NegDoubleFieldLargeNegativeExponentParsesAsNegZero.ProtobufOutput
Required.Proto3.TextFormatInput.NegDoubleFieldLargeNegativeExponentParsesAsNegZero.TextFormatOutput
Required.Proto3.TextFormatInput.NegFloatFieldLargeNegativeExponentParsesAsNegZero.ProtobufOutput
Required.Proto3.TextFormatInput.NegFloatFieldLargeNegativeExponentParsesAsNegZero.TextFormatOutput

@ -1,8 +1,72 @@
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.TextFormatOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatField_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatField_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldLargerThanInt64_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldLargerThanInt64_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldLargerThanUint64_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldLargerThanUint64_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMaxValue_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMaxValue_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMinValue_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMinValue_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegative_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegative_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeNoLeadingZero_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeNoLeadingZero_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoLeadingZero_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoLeadingZero_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoLeadingZeroWithExponent_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoLeadingZeroWithExponent_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoNegativeOctal
Required.Editions_Proto3.TextFormatInput.FloatFieldNoOctal
Required.Editions_Proto3.TextFormatInput.FloatFieldTooLarge_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldTooLarge_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldTooSmall_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldTooSmall_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldWithInt32Max_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldWithInt32Max_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldWithVeryPreciseNumber_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldWithVeryPreciseNumber_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldZero_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldZero_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeZero_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeZero_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.StringLiteralBasicEscapesString.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.StringLiteralBasicEscapesString.TextFormatOutput
Required.Proto3.TextFormatInput.FloatField_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatField_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanInt64_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanInt64_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanUint64_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanUint64_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldMaxValue_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldMaxValue_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldMinValue_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldMinValue_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNegative_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNegative_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeNoLeadingZero_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeNoLeadingZero_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNoLeadingZero_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNoLeadingZero_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNoLeadingZeroWithExponent_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNoLeadingZeroWithExponent_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNoNegativeOctal
Required.Proto3.TextFormatInput.FloatFieldNoOctal
Required.Proto3.TextFormatInput.FloatFieldTooLarge_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldTooLarge_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldTooSmall_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldTooSmall_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldWithInt32Max_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldWithInt32Max_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldWithVeryPreciseNumber_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldWithVeryPreciseNumber_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldZero_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldZero_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeZero_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeZero_F.TextFormatOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.TextFormatOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.TextFormatOutput

@ -1,11 +1,75 @@
# This is the list of text format conformance tests that are known to fail right
# now.
# TODO: These should be fixed.
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.TextFormatOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatField_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatField_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldLargerThanInt64_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldLargerThanInt64_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldLargerThanUint64_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldLargerThanUint64_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMaxValue_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMaxValue_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMinValue_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldMinValue_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegative_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegative_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeNoLeadingZero_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeNoLeadingZero_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeZero_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNegativeZero_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoLeadingZero_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoLeadingZero_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoLeadingZeroWithExponent_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoLeadingZeroWithExponent_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldNoNegativeOctal
Required.Editions_Proto3.TextFormatInput.FloatFieldNoOctal
Required.Editions_Proto3.TextFormatInput.FloatFieldTooLarge_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldTooLarge_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldTooSmall_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldTooSmall_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldWithInt32Max_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldWithInt32Max_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldWithVeryPreciseNumber_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldWithVeryPreciseNumber_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldZero_F.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.FloatFieldZero_F.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.StringLiteralBasicEscapesString.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.StringLiteralBasicEscapesString.TextFormatOutput
Required.Proto3.TextFormatInput.FloatField_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatField_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanInt64_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanInt64_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanUint64_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldLargerThanUint64_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldMaxValue_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldMaxValue_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldMinValue_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldMinValue_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNegative_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNegative_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeNoLeadingZero_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeNoLeadingZero_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeZero_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNegativeZero_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNoLeadingZero_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNoLeadingZero_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNoLeadingZeroWithExponent_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldNoLeadingZeroWithExponent_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldNoNegativeOctal
Required.Proto3.TextFormatInput.FloatFieldNoOctal
Required.Proto3.TextFormatInput.FloatFieldTooLarge_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldTooLarge_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldTooSmall_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldTooSmall_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldWithInt32Max_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldWithInt32Max_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldWithVeryPreciseNumber_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldWithVeryPreciseNumber_F.TextFormatOutput
Required.Proto3.TextFormatInput.FloatFieldZero_F.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldZero_F.TextFormatOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.TextFormatOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.TextFormatOutput

@ -900,6 +900,42 @@ namespace Google.Protobuf
AssertWriteValue(value, "[\n 1,\n 2,\n 3\n]", JsonFormatter.Settings.Default.WithIndentation());
}
[Test]
public void WriteValueWithIndentation_Any()
{
var registry = TypeRegistry.FromMessages(ForeignMessage.Descriptor);
var formatter = JsonFormatter.Settings.Default.WithIndentation().WithTypeRegistry(registry);
var nestedMessage = new ForeignMessage { C = 1 };
var value = Any.Pack(nestedMessage);
const string expectedJson = @"
{
'@type': 'type.googleapis.com/protobuf_unittest3.ForeignMessage',
'c': 1
}";
AssertWriteValue(value, expectedJson, formatter);
}
[Test]
public void WriteValueWithIndentation_NestedAny()
{
var registry = TypeRegistry.FromMessages(ForeignMessage.Descriptor);
var formatter = JsonFormatter.Settings.Default.WithIndentation().WithTypeRegistry(registry);
var nestedMessage = new ForeignMessage { C = 1 };
var value = new TestWellKnownTypes { AnyField = Any.Pack(nestedMessage) };
const string expectedJson = @"
{
'anyField': {
'@type': 'type.googleapis.com/protobuf_unittest3.ForeignMessage',
'c': 1
}
}";
AssertWriteValue(value, expectedJson, formatter);
}
[Test]
public void WriteValueWithIndentation_CustomIndentation()
{

@ -137,6 +137,16 @@ namespace Google.Protobuf.Test.Reflection
Assert.AreEqual(" Zero value comment\n", value.Declaration.LeadingComments);
}
[Test]
public void OneofComments()
{
// CommentMessage doesn't have an enum, but we can use TestAllTypes.
var message = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("TestAllTypes");
var oneof = message.Oneofs.Single(o => o.Name == "oneof_field");
Assert.NotNull(oneof.Declaration);
Assert.AreEqual(" For oneof test\n", oneof.Declaration.LeadingComments);
}
private static FileDescriptor LoadProtos()
{
var type = typeof(DescriptorDeclarationTest);

@ -204,6 +204,14 @@ namespace Google.Protobuf.Reflection
TestDescriptorToProto(messageType.ToProto, messageType.Proto);
}
[Test]
public void MessageDescriptor_IsMapEntry()
{
var testMapMessage = TestMap.Descriptor;
Assert.False(testMapMessage.IsMapEntry);
Assert.True(testMapMessage.Fields[1].MessageType.IsMapEntry);
}
[Test]
public void FieldDescriptor_GeneratedCode()
{

@ -481,6 +481,7 @@ namespace Google.Protobuf {
}
IMessage message = descriptor.Parser.ParseFrom(data);
WriteBracketOpen(writer, ObjectOpenBracket);
MaybeWriteValueWhitespace(writer, indentationLevel + 1);
WriteString(writer, AnyTypeUrlField);
writer.Write(NameValueSeparator);
WriteString(writer, typeUrl);
@ -489,9 +490,9 @@ namespace Google.Protobuf {
writer.Write(ValueSeparator);
WriteString(writer, AnyWellKnownTypeValueField);
writer.Write(NameValueSeparator);
WriteWellKnownTypeValue(writer, descriptor, message, indentationLevel);
WriteWellKnownTypeValue(writer, descriptor, message, indentationLevel + 1);
} else {
WriteMessageFields(writer, message, true, indentationLevel);
WriteMessageFields(writer, message, true, indentationLevel + 1);
}
WriteBracketClose(writer, ObjectCloseBracket, true, indentationLevel);
}

@ -242,7 +242,7 @@ namespace Google.Protobuf.Reflection
/// <summary>
/// Returns <c>true</c> if this field is a map field; <c>false</c> otherwise.
/// </summary>
public bool IsMap => FieldType == FieldType.Message && messageType.Proto.Options != null && messageType.Proto.Options.MapEntry;
public bool IsMap => FieldType == FieldType.Message && messageType.IsMapEntry;
/// <summary>
/// Returns <c>true</c> if this field is a packed, repeated field; <c>false</c> otherwise.
@ -379,7 +379,12 @@ namespace Google.Protobuf.Reflection
IDescriptor typeDescriptor =
File.DescriptorPool.LookupSymbol(Proto.TypeName, this);
// TODO: See how much of this is actually required.
// In most cases, the type will be specified in the descriptor proto. This may be
// guaranteed in descriptor.proto in the future (with respect to spring 2024), but
// we may still see older descriptors created by old versions of protoc, and there
// may be some code creating descriptor protos directly. This code effectively
// maintains backward compatibility, but we don't expect it to be a path taken
// often at all.
if (!Proto.HasType)
{
// Choose field type based on symbol.

@ -119,6 +119,7 @@ namespace Google.Protobuf.Reflection
DescriptorProto.FieldFieldNumber => (IReadOnlyList<DescriptorBase>)fieldsInDeclarationOrder,
DescriptorProto.NestedTypeFieldNumber => (IReadOnlyList<DescriptorBase>)NestedTypes,
DescriptorProto.EnumTypeFieldNumber => (IReadOnlyList<DescriptorBase>)EnumTypes,
DescriptorProto.OneofDeclFieldNumber => (IReadOnlyList<DescriptorBase>)Oneofs,
_ => null,
};
@ -201,6 +202,12 @@ namespace Google.Protobuf.Reflection
/// </summary>
internal bool IsWrapperType => File.Package == "google.protobuf" && File.Name == "google/protobuf/wrappers.proto";
/// <summary>
/// Returns whether this message was synthetically-created to store key/value pairs in a
/// map field.
/// </summary>
public bool IsMapEntry => Proto.Options?.MapEntry == true;
/// <value>
/// If this is a nested type, get the outer descriptor, otherwise null.
/// </value>

@ -37,4 +37,5 @@ The following topics are in this repository:
* [Edition Naming](edition-naming.md)
* [Editions Feature Visibility](editions-feature-visibility.md)
* [Legacy Syntax Editions](legacy-syntax-editions.md)
* [Editions: Feature Extension Layout](editions-feature-extension-layout.md)
* [Editions: Feature Extension Layout](editions-feature-extension-layout.md)
* [Editions: Group Migration Issues](group-migration-issues.md)

@ -0,0 +1,401 @@
# Editions: Group Migration Issues
**Authors**: [@mkruskal-google](https://github.com/mkruskal-google)
## Summary
Address some unexpected issues in delimited encoding in edition 2023 before its
OSS release.
## Background
Joshua Humphries reported some well-timed
[issues](https://github.com/protocolbuffers/protobuf/issues/16239) discovered
while experimenting with our early release of Edition 2023. He discovered that
our new message encoding feature piggybacked a bit too much on the old group
logic, and actually ended up being virtually useless in general.
None of our testing or migrations caught this because they were heavily focused
on *preserving* old behavior (which is the primary goal of edition 2023).
Delimited messages structured exactly like proto2 groups (e.g. message and field
in the same scope with matching names) continued to work exactly as before,
making it seem like everything was fine.
All of this is especially problematic in light of *Submessages: In Pursuit of a
More Perfect Encoding* (not available externally yet), which intends to migrate the
ecosystem to use delimited encoding everywhere. Releasing a semi-broken feature
as a migration tool to eliminate a deprecated syntax is one thing, but trying to
push the ecosystem to it is especially bad.
## Overview
The problems here stem from the fact that before edition 2023, the field and
type name of group fields was guaranteed to always be unique and intuitive.
Proto2 splits groups into a synthetic nested message with a type name equivalent
to the group specification (required to be capitalized), and a field name that's
fully lowercased. For example,
```
optional group MyGroup = 1 { ... }
```
would become:
```
message MyGroup { ... }
optional MyGroup mygroup = 1;
```
The casing here is very important, since the transformation is irreversible. We
can't recover the group name from the field name in general, only if the group
is a single word.
The problem under edition 2023 is that we've removed the generation of
synchronized synthetic messages from the language. Users now explicitly define
messages, and any message field can be marked `DELIMITED`. This means that
anyone assuming that the type and field name are synchronized could now be
broken.
### Codegen
While using the field name for generated APIs required less special-casing in
the generators, the field name ends up producing slightly-less-readable APIs for
multi-word camelcased groups. The result is that we see a fairly random-seeming
mix in different generators. Using protoc-explorer (not available externally),
we find the following:
<table>
<tr>
<td><strong>Language</strong>
</td>
<td><strong>Generated APIs</strong>
</td>
<td><strong>Example proto2 getter</strong>
</td>
</tr>
<tr>
<td>C++
</td>
<td>field
</td>
<td><code>MyGroup mygroup()</code>
</td>
</tr>
<tr>
<td>Java (all)
</td>
<td>message
</td>
<td><code>MyGroup getMyGroup()</code>
</td>
</tr>
<tr>
<td>Python
</td>
<td>field
</td>
<td><code>mygroup</code>
</td>
</tr>
<tr>
<td>Go (all)
</td>
<td>field
</td>
<td><code>GetMygroup() *Foo_MyGroup</code>
</td>
</tr>
<tr>
<td>Dart V1
</td>
<td>field/message*
</td>
<td><code>get mygroup</code>
</td>
</tr>
<tr>
<td>upb **
</td>
<td>field
</td>
<td><code>Foo_mygroup()</code>
</td>
</tr>
<tr>
<td>Objective-c
</td>
<td>message
</td>
<td><code>MyGroup* myGroup</code>
</td>
</tr>
<tr>
<td>Swift
</td>
<td>message
</td>
<td><code>MyGroup myGroup</code>
</td>
</tr>
<tr>
<td>C#
</td>
<td>field/message*
</td>
<td><code>MyGroup Mygroup</code>
</td>
</tr>
</table>
\* This codegen difference was [caught](cl/611144002) during the implementation
and intentionally "fixed" in Edition 2023. \
\*\* This includes all upb-based runtimes as well (e.g. Ruby, Rust, etc.) \
† Extensions use field
In the Dart V1 implementation, we decided to intentionally introduce a behavior
change on editions upgrades. It was determined that this only affected a handful
of protos in google3, and could probably be manually fixed as-needed. Java's
handling changes the story significantly, since over 50% of protos in google3
produce generated Java code. Objective-C is also noteworthy since we open-source
it, and Swift because it's widely used in OSS and we don't own it.
While the editions upgrade is still non-breaking, it means that the generated
APIs could have very surprising spellings and may not be unique. For example,
using the same type for two delimited fields in the same containing message will
create two sets of generated APIs with the same name in some languages!
### Text Format
Our "official"
[draft specification](https://protobuf.dev/reference/protobuf/textformat-spec/)
of text-format explicitly states that group messages are encoded by the *message
name*, rather than the lowercases field name. A group `MyGroup` will be
serialized as:
```
MyGroup {
...
}
```
In C++, we always serialize the message name and have special handling to only
accept the message name in parsing. We also have conformance tests locking down
the positive path here (i.e. using the message name round-trip). The negative
path (i.e. failing to accept the field name) doesn't have a conformance test,
but C++/Java/Python all agree and there's no known case that doesn't.
To make things even stranger, for *extensions* (group fields extending other
messages), we always use the field name for groups. So as far as group
extensions are concerned, there's no problem for editions.
There are a few problems with non-extension group fields in editions:
* Refactoring the message name will change any text-format output
* New delimited fields will have unexpected text-format output, that *could*
conflict with other fields
* Text parsers will expect the message name, which is surprising and could be
impossible to specify uniquely
## Recommendation
Clearly the end-state we want is for the field name to be used in all generated
APIs, and for text-format serialization/parsing. The only questions are: how do
we get there and can/should we do it in time for the 2023 release in 27.0 next
month?
We propose a combination of the alternatives listed below.
[Smooth Extension](#smooth-extension) seems like the best short-term path
forward to unblock the delimited migration. It *mostly* solves the problem and
doesn't require any new features. The necessary changes for this approach have
already been prepared, along with new conformance tests to lock down the
behavior changes.
[Global Feature](#global-feature) is a good long-term mitigation for tech debt
we're leaving behind with *Smooth Extension*. Ultimately we would like to remove
any labeling of fields by their type, and editions provides a good mechanism to
do this. Alternatively, we could implement [aliases](#aliases) and use that to
unify this old behavior and avoid a new feature. Either of these options will be
the next step after the release of 2023, with aliases being preferred as long as
the timing works out.
If we hit any unexpected delays, Nerf Delimited Encoding in 2023 (not available
externally) is the quickest path forward to unblock the release of edition 2023.
It has a lot of downsides though, and will block any migration towards delimited
encoding until edition 2024 has started rolling out.
## Alternatives
### Smooth Extension {#smooth-extension}
Instead of trying to change the existing behavior, we could expand the current
spec to try to cover both proto2 and editions. We would define a "group-like"
concept, which applies to all fields which:
* Have `DELIMITED` encoding
* Have a type corresponding to a nested message directly under its containing
message
* Have a name corresponding to its lowercased type name.
Note that proto2 groups will *always* be "group-like."
For any group-like field we will use the old proto2 semantics, whatever they are
today. Otherwise, we will treat them as regular fields for both codegen and
text-format. This means that *most* new cases of delimited encoding will have
the desired behavior, while *all* old groups will continue to function. The main
exception here is that users will see the unexpected proto2 behavior if they
have message/field names that *happen* to match.
While the old behavior will result in some unexpected capitalization when it's
hit, it's mostly safe. Because of 2 and 3 (and the fact that we disallow
duplicate field names), we can guarantee that in both codegen and text encoding
there will never be any conflicting symbols. There can never be two delimited
fields of the same type using the old behavior, and no other messages or fields
will exist with either spelling.
Additionally, we will update the text parsers to accept **both** the old
message-based spelling and the new field-based spelling for group-like fields.
This will at least prevent parsing failures if users hit this unexpected change
in behavior.
#### Pros
* Fully supports old proto2 behavior
* Treats most new editions fields correctly
* Doesn't allow for any of the problematic cases we see today
* By updating the parsers to accept both, we have a migration path to change
the "wire"-format
* Decoupled from editions launch (since it's a non-breaking change w/o a
feature)
#### Cons
* Requires coordinated changes in every editions-compatible runtime (and many
generators)
* Keeps the old proto2 behavior around indefinitely, with no path to remove it
* Plants surprising edge case for users if they happen to name their
message/fields a certain way
### Global Feature {#global-feature}
The simplest answer here is to introduce a new global message feature
`legacy_group_handling` to control all the changes we'd like. This will only be
applicable to group-like fields (see
[Smooth Extension](?tab=t.0#heading=h.blnhard1tpyx)). With this feature enabled,
these fields will always use their message name for text-format. Each
non-conformant language could also use this feature to gate the codegen rules.
#### Pros
* Simple boolean to gate all the behavior changes
* Doesn't require adding language features to a bunch of languages that don't
have them yet
* Uses editions to ratchet down the bad behavior
#### Cons
* It's a little late in the game to be introducing new features to 2023
(go/edition-lifetimes)
* Requires coordinated changes in every editions-compatible runtime (and many
generators)
* The migration story for users is unclear. Overriding the value of this
feature is both a "wire"-breaking and API-breaking change they may not be
able to do easily.
* With the feature set, users will still see all of the problems we have today
### Feature Suite
An extension of [Global feature](?tab=t.0#heading=h.mvtf74vplkdg) would be to
split the codegen changes out into separate per-language features.
#### Pros
* Simple booleans to gate all the distinct behavior changes
* Uses editions to ratchet down the bad behavior
* Better migration story for users, since it separates API and "wire" breaking
changes
#### Cons
* Requires a whole slew of new language features, which typically have a
difficult first-time setup
* Requires coordinated changes in every editions-compatible runtime (and many
generators)
* Increases the complexity of edition 2023 significantly
* With the features set, users will still see all of the problems we have
today
### Nerf Delimited Encoding in 2023
A quick fix to avoid releasing a bad feature would be to simply ban the case
where the message and field names don't match. Adding this validation to protoc
would cover the majority of cases, although we might want additional checks in
every language that supports dynamic messages.
This is a good fallback option if we can't implement anything better before 27.0
is released. It allows us to release editions in a reasonable state, where we
can fix these issues and release a more functional `DELIMITED` feature in 2024.
#### Pros
* Unblocks editions rollout
* Easy and safe to implement
* Avoids rushed implementation of a proper fix
* Avoids runtime issues with text format
* Avoids unexpected build breakages post-editions (e.g. renaming the nested
message)
#### Cons
* We'd still be releasing a really bad feature. Instead of opening up new
possibilities, it's just "like groups but worse"
* We couldn't fix this in 2023 without potential version skew from third party
plugins. We'd likely have to wait until edition 2024
* Might requires coordinated changes in a lot of runtimes
* Doesn't unblock our effort to roll out delimited
### Rename Fields in Editions
While it might be tempting to leverage the edition 2023 upgrade as a place we
can just rename the group field, that doesn't actually work (e.g. rename
`mygroup` to `my_group`). Because so many runtimes already use the *field name*
in generated APIs, they would break under this transformation.
#### Pros
* Works really well for text-format and some languages
#### Cons
* Turns 2023 upgrade into a breaking change for many languages
### Aliases {#aliases}
We've discussed aliases a lot mostly in the context of `Any`, but they would be
useful for any encoding scheme that locks down field/message names. If we had a
fully implemented alias system in place, it would be the perfect mitigation
here. Unfortunately, we don't yet and the timeline here is probably too tight to
implement one.
#### Pros
* Fixes all of the problems mentioned above
* Allows us to specify the old behavior using the proto language, which allows
it to be handled by Prototiller
#### Cons
* We want this to be a real fully thought-out feature, not a hack rushed into
a tight timeline
### Do Nothing
Doing nothing doesn't actually break anyone, but it is embarrassing.
#### Pros
* Easy to do
#### Cons
* Releases a horrible feature full of foot-guns in our first edition
* Doesn't unblock our effort to roll out delimited

@ -187,6 +187,7 @@ Inactive:
[![Maven Central](https://img.shields.io/maven-central/v/org.xolstice.maven.plugins/protobuf-maven-plugin.svg)](https://repo1.maven.org/maven2/org/xolstice/maven/plugins/protobuf-maven-plugin/)
* https://code.google.com/p/maven-protoc-plugin/
* https://github.com/os72/protoc-jar-maven-plugin
* https://ascopes.github.io/protobuf-maven-plugin
* [Protobuf Plugin for Gradle](https://github.com/google/protobuf-gradle-plugin)
* [Sbt plugin for Protocol Buffers](https://github.com/Atry/sbt-cppp)

@ -1,5 +1,5 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("//:protobuf.bzl", "internal_objc_proto_library", "internal_py_proto_library")
load("//:protobuf.bzl", "internal_objc_proto_library", "internal_php_proto_library", "internal_py_proto_library")
load("//bazel:cc_proto_library.bzl", "cc_proto_library")
load("//bazel:upb_proto_library.bzl", "upb_c_proto_library", "upb_proto_reflection_library")
load(":defaults.bzl", "compile_edition_defaults", "embed_edition_defaults")
@ -236,6 +236,31 @@ java_lite_proto_library(
deps = [":test_messages_proto3_editions_proto"],
)
internal_php_proto_library(
name = "test_messages_proto3_editions_php_proto",
testonly = 1,
srcs = ["golden/test_messages_proto3_editions.proto"],
outs = [
"GPBMetadata/TestMessagesProto3Editions.php",
"Protobuf_test_messages/Editions/Proto3/EnumOnlyProto3.php",
"Protobuf_test_messages/Editions/Proto3/EnumOnlyProto3/PBBool.php",
"Protobuf_test_messages/Editions/Proto3/ForeignEnum.php",
"Protobuf_test_messages/Editions/Proto3/ForeignMessage.php",
"Protobuf_test_messages/Editions/Proto3/NullHypothesisProto3.php",
"Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3.php",
"Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3/AliasedEnum.php",
"Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3/NestedEnum.php",
"Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3/NestedMessage.php",
],
enable_editions = True,
includes = [
"golden",
"src",
],
proto_deps = ["//:well_known_protos"],
visibility = ["//conformance:__pkg__"],
)
internal_py_proto_library(
name = "test_messages_proto3_editions_py_pb2",
testonly = True,
@ -260,7 +285,7 @@ upb_proto_reflection_library(
deps = ["test_messages_proto3_editions_proto"],
)
# Export these for conformance tests for ruby codegen.
# Export these for conformance tests for ruby and C# codegen.
exports_files(
[
"golden/test_messages_proto2_editions.proto",
@ -268,6 +293,7 @@ exports_files(
],
visibility = [
"//ruby:__pkg__",
"//src/google/protobuf/csharp:__pkg__",
],
)

@ -25,14 +25,14 @@
target = ::proto2::internal::WireFormatLite::
WriteInt32ToArrayWithField<1>(
@@ @@
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
(void)cached_has_bits;
- // optional int32 int32_field = 1;
+ // int32 int32_field = 1;
cached_has_bits = _impl_._has_bits_[0];
if (cached_has_bits & 0x00000001u) {
total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(
{
- // optional int32 int32_field = 1;
+ // int32 int32_field = 1;
cached_has_bits = _impl_._has_bits_[0];
if (cached_has_bits & 0x00000001u) {
total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(
[ FAILED ] third_party/protobuf/editions/golden/simple_proto3.pb.cc
[ RUN ] third_party/protobuf/editions/golden/simple_proto3.pb.h
@@ @@

@ -2,10 +2,10 @@
<testsuites tests="1" name="AllTests">
<testsuite name="EditionsCodegenTests">
<testcase name="third_party/protobuf/editions/golden/simple_proto3.pb.cc" status="run" result="completed" classname="DiffTest">
<failure message="Value of: third_party/protobuf/editions/golden/simple_proto3.pb.cc&#x0A;Expected: &#x0A;// Generated by the protocol buffer compiler. DO NOT EDIT!&#x0A;// NO CHECKED-IN PROTOBUF GENCODE&#x0A;// source: third_party/protobuf/editions/golden/simple_proto3.proto&#x0A;// Protobuf C++ Version: 0.20240410.0&#x0A;&#x0A;#include &quot;third_party/protobuf/editions/golden/simple_proto3.pb.h&quot;&#x0A;&#x0A;#include &lt;algorithm&gt;&#x0A;#include &lt;type_traits&gt;&#x0A;#include &quot;third_party/protobuf/io/coded_stream.h&quot;&#x0A;#include &quot;third_party/protobuf/generated_message_tctable_impl.h&quot;&#x0A;#include &quot;third_party/protobuf/extension_set.h&quot;&#x0A;#include &quot;third_party/protobuf/wire_format_lite.h&quot;&#x0A;#include &quot;third_party/protobuf/io/zero_copy_stream_impl_lite.h&quot;&#x0A;// @@protoc_insertion_point(includes)&#x0A;&#x0A;// Must be included last.&#x0A;, with the difference:&#x0A;@@ @@&#x0A; ::_pbi::TcParser::GetTable&lt;::protobuf_editions_test::golden::SimpleProto3&gt;(), // to_prefetch&#x0A; #endif // PROTOBUF_PREFETCH_PARSE_TABLE&#x0A; }, {{&#x0A;- // optional int32 int32_field = 1;&#x0A;+ // int32 int32_field = 1;&#x0A; {::_pbi::TcParser::FastV32S1,&#x0A; {8, 0, 0, PROTOBUF_FIELD_OFFSET(SimpleProto3, _impl_.int32_field_)}},&#x0A; }}, {{&#x0A; 65535, 65535&#x0A; }}, {{&#x0A;- // optional int32 int32_field = 1;&#x0A;+ // int32 int32_field = 1;&#x0A; {PROTOBUF_FIELD_OFFSET(SimpleProto3, _impl_.int32_field_), _Internal::kHasBitsOffset + 0, 0,&#x0A; (0 | ::_fl::kFcOptional | ::_fl::kInt32)},&#x0A; }},&#x0A;@@ @@&#x0A; (void)cached_has_bits;&#x0A; &#x0A; cached_has_bits = _impl_._has_bits_[0];&#x0A;- // optional int32 int32_field = 1;&#x0A;+ // int32 int32_field = 1;&#x0A; if (cached_has_bits &amp; 0x00000001u) {&#x0A; target = ::proto2::internal::WireFormatLite::&#x0A; WriteInt32ToArrayWithField&lt;1&gt;(&#x0A;@@ @@&#x0A; // Prevent compiler warnings about cached_has_bits being unused&#x0A; (void) cached_has_bits;&#x0A; &#x0A;- // optional int32 int32_field = 1;&#x0A;+ // int32 int32_field = 1;&#x0A; cached_has_bits = _impl_._has_bits_[0];&#x0A; if (cached_has_bits &amp; 0x00000001u) {&#x0A; total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(" type=""></failure>
<failure message="Value of: third_party/protobuf/editions/golden/simple_proto3.pb.cc&#x0A;Expected: &#x0A;// Generated by the protocol buffer compiler. DO NOT EDIT!&#x0A;// NO CHECKED-IN PROTOBUF GENCODE&#x0A;// source: third_party/protobuf/editions/golden/simple_proto3.proto&#x0A;// Protobuf C++ Version: 0.20240502.0&#x0A;&#x0A;#include &quot;third_party/protobuf/editions/golden/simple_proto3.pb.h&quot;&#x0A;&#x0A;#include &lt;algorithm&gt;&#x0A;#include &lt;type_traits&gt;&#x0A;#include &quot;third_party/protobuf/io/coded_stream.h&quot;&#x0A;#include &quot;third_party/protobuf/generated_message_tctable_impl.h&quot;&#x0A;#include &quot;third_party/protobuf/extension_set.h&quot;&#x0A;#include &quot;third_party/protobuf/wire_format_lite.h&quot;&#x0A;#include &quot;third_party/protobuf/io/zero_copy_stream_impl_lite.h&quot;&#x0A;// @@protoc_insertion_point(includes)&#x0A;&#x0A;// Must be included last.&#x0A;, with the difference:&#x0A;@@ @@&#x0A; ::_pbi::TcParser::GetTable&lt;::protobuf_editions_test::golden::SimpleProto3&gt;(), // to_prefetch&#x0A; #endif // PROTOBUF_PREFETCH_PARSE_TABLE&#x0A; }, {{&#x0A;- // optional int32 int32_field = 1;&#x0A;+ // int32 int32_field = 1;&#x0A; {::_pbi::TcParser::FastV32S1,&#x0A; {8, 0, 0, PROTOBUF_FIELD_OFFSET(SimpleProto3, _impl_.int32_field_)}},&#x0A; }}, {{&#x0A; 65535, 65535&#x0A; }}, {{&#x0A;- // optional int32 int32_field = 1;&#x0A;+ // int32 int32_field = 1;&#x0A; {PROTOBUF_FIELD_OFFSET(SimpleProto3, _impl_.int32_field_), _Internal::kHasBitsOffset + 0, 0,&#x0A; (0 | ::_fl::kFcOptional | ::_fl::kInt32)},&#x0A; }},&#x0A;@@ @@&#x0A; (void)cached_has_bits;&#x0A; &#x0A; cached_has_bits = _impl_._has_bits_[0];&#x0A;- // optional int32 int32_field = 1;&#x0A;+ // int32 int32_field = 1;&#x0A; if (cached_has_bits &amp; 0x00000001u) {&#x0A; target = ::proto2::internal::WireFormatLite::&#x0A; WriteInt32ToArrayWithField&lt;1&gt;(&#x0A;@@ @@&#x0A; (void)cached_has_bits;&#x0A; &#x0A; {&#x0A;- // optional int32 int32_field = 1;&#x0A;+ // int32 int32_field = 1;&#x0A; cached_has_bits = _impl_._has_bits_[0];&#x0A; if (cached_has_bits &amp; 0x00000001u) {&#x0A; total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(" type=""></failure>
</testcase>
<testcase name="third_party/protobuf/editions/golden/simple_proto3.pb.h" status="run" result="completed" classname="DiffTest">
<failure message="Value of: third_party/protobuf/editions/golden/simple_proto3.pb.h&#x0A;Expected: &#x0A;// Generated by the protocol buffer compiler. DO NOT EDIT!&#x0A;// NO CHECKED-IN PROTOBUF GENCODE&#x0A;// source: third_party/protobuf/editions/golden/simple_proto3.proto&#x0A;// Protobuf C++ Version: 0.20240410.0&#x0A;&#x0A;#ifndef GOOGLE_PROTOBUF_INCLUDED_third_5fparty_2fprotobuf_2feditions_2fgolden_2fsimple_5fproto3_2eproto_2epb_2eh&#x0A;#define GOOGLE_PROTOBUF_INCLUDED_third_5fparty_2fprotobuf_2feditions_2fgolden_2fsimple_5fproto3_2eproto_2epb_2eh&#x0A;&#x0A;#include &lt;limits&gt;&#x0A;#include &lt;string&gt;&#x0A;#include &lt;type_traits&gt;&#x0A;#include &lt;utility&gt;&#x0A;&#x0A;#include &quot;third_party/protobuf/runtime_version.h&quot;&#x0A;#if PROTOBUF_VERSION != 20240410&#x0A;#error &quot;Protobuf C++ gencode is built with an incompatible version of&quot;&#x0A;#error &quot;Protobuf C++ headers/runtime. See&quot;&#x0A;#error &quot;https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp&quot;&#x0A;#endif&#x0A;#include &quot;third_party/protobuf/io/coded_stream.h&quot;&#x0A;#include &quot;third_party/protobuf/arena.h&quot;&#x0A;#include &quot;third_party/protobuf/arenastring.h&quot;&#x0A;#include &quot;third_party/protobuf/generated_message_tctable_decl.h&quot;&#x0A;#include &quot;third_party/protobuf/generated_message_util.h&quot;&#x0A;#include &quot;third_party/protobuf/metadata_lite.h&quot;&#x0A;#include &quot;third_party/protobuf/message_lite.h&quot;&#x0A;// @@protoc_insertion_point(includes)&#x0A;&#x0A;// Must be included last.&#x0A;&#x0A;#endif // GOOGLE_PROTOBUF_INCLUDED_third_5fparty_2fprotobuf_2feditions_2fgolden_2fsimple_5fproto3_2eproto_2epb_2eh&#x0A;, with the difference:&#x0A;@@ @@&#x0A; enum : int {&#x0A; kInt32FieldFieldNumber = 1,&#x0A; };&#x0A;- // optional int32 int32_field = 1;&#x0A;+ // int32 int32_field = 1;&#x0A; bool has_int32_field() const;&#x0A; void clear_int32_field() ;&#x0A; ::int32_t int32_field() const;&#x0A;@@ @@&#x0A; &#x0A; // SimpleProto3&#x0A; &#x0A;-// optional int32 int32_field = 1;&#x0A;+// int32 int32_field = 1;&#x0A; inline bool SimpleProto3::has_int32_field() const {&#x0A; bool value = (_impl_._has_bits_[0] &amp; 0x00000001u) != 0;&#x0A; return value;" type=""></failure>
<failure message="Value of: third_party/protobuf/editions/golden/simple_proto3.pb.h&#x0A;Expected: &#x0A;// Generated by the protocol buffer compiler. DO NOT EDIT!&#x0A;// NO CHECKED-IN PROTOBUF GENCODE&#x0A;// source: third_party/protobuf/editions/golden/simple_proto3.proto&#x0A;// Protobuf C++ Version: 0.20240502.0&#x0A;&#x0A;#ifndef GOOGLE_PROTOBUF_INCLUDED_third_5fparty_2fprotobuf_2feditions_2fgolden_2fsimple_5fproto3_2eproto_2epb_2eh&#x0A;#define GOOGLE_PROTOBUF_INCLUDED_third_5fparty_2fprotobuf_2feditions_2fgolden_2fsimple_5fproto3_2eproto_2epb_2eh&#x0A;&#x0A;#include &lt;limits&gt;&#x0A;#include &lt;string&gt;&#x0A;#include &lt;type_traits&gt;&#x0A;#include &lt;utility&gt;&#x0A;&#x0A;#include &quot;third_party/protobuf/runtime_version.h&quot;&#x0A;#if PROTOBUF_VERSION != 20240502&#x0A;#error &quot;Protobuf C++ gencode is built with an incompatible version of&quot;&#x0A;#error &quot;Protobuf C++ headers/runtime. See&quot;&#x0A;#error &quot;https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp&quot;&#x0A;#endif&#x0A;#include &quot;third_party/protobuf/io/coded_stream.h&quot;&#x0A;#include &quot;third_party/protobuf/arena.h&quot;&#x0A;#include &quot;third_party/protobuf/arenastring.h&quot;&#x0A;#include &quot;third_party/protobuf/generated_message_tctable_decl.h&quot;&#x0A;#include &quot;third_party/protobuf/generated_message_util.h&quot;&#x0A;#include &quot;third_party/protobuf/metadata_lite.h&quot;&#x0A;#include &quot;third_party/protobuf/message_lite.h&quot;&#x0A;// @@protoc_insertion_point(includes)&#x0A;&#x0A;// Must be included last.&#x0A;&#x0A;#endif // GOOGLE_PROTOBUF_INCLUDED_third_5fparty_2fprotobuf_2feditions_2fgolden_2fsimple_5fproto3_2eproto_2epb_2eh&#x0A;, with the difference:&#x0A;@@ @@&#x0A; enum : int {&#x0A; kInt32FieldFieldNumber = 1,&#x0A; };&#x0A;- // optional int32 int32_field = 1;&#x0A;+ // int32 int32_field = 1;&#x0A; bool has_int32_field() const;&#x0A; void clear_int32_field() ;&#x0A; ::int32_t int32_field() const;&#x0A;@@ @@&#x0A; &#x0A; // SimpleProto3&#x0A; &#x0A;-// optional int32 int32_field = 1;&#x0A;+// int32 int32_field = 1;&#x0A; inline bool SimpleProto3::has_int32_field() const {&#x0A; bool value = (_impl_._has_bits_[0] &amp; 0x00000001u) != 0;&#x0A; return value;" type=""></failure>
</testcase>
<testcase name="third_party/protobuf/editions/golden/simple_proto3.proto.static_reflection.h" status="run" result="completed" classname="DiffTest">
</testcase>

@ -15,7 +15,7 @@ edition = "2023";
package protobuf_editions_test;
import "net/proto/proto1_features.proto";
import "third_party/java/protobuf/java_features.proto";
import "google/protobuf/java_features.proto";
import "google/protobuf/cpp_features.proto";
import "google/protobuf/editions/proto/editions_transform_proto3.proto";

@ -1 +1,9 @@
build --cxxopt=-std=c++14 --host_cxxopt=-std=c++14
common --enable_platform_specific_config
build:linux --cxxopt=-std=c++14 --host_cxxopt=-std=c++14
build:macos --cxxopt=-std=c++14 --host_cxxopt=-std=c++14
common:windows --enable_runfiles
build --experimental_remote_cache_eviction_retries=5
build --remote_download_outputs=all

@ -67,8 +67,36 @@ If you are contributing code to protobuf or want to use a protobuf version
that hasn't been officially released yet, you can follow the instructions
below to build protobuf from source code.
### Build from Source
You may follow these instructions to build from source. This does not require
Maven to be installed. Note that these instructions skip running unit tests and
only describes how to install the core protobuf library (without the util
package).
1) Build the C++ code, or obtain a binary distribution of protoc (see
the toplevel [README.md](../README.md)). If you install a binary
distribution, make sure that it is the same version as this package.
If in doubt, run:
$ protoc --version
If you built the C++ code without installing, the compiler binary
should be located in ../src.
2) Invoke protoc to build DescriptorProtos.java:
$ protoc --java_out=core/src/main/java -I../src \
../src/google/protobuf/descriptor.proto
3) Compile the code in core/src/main/java using whatever means you prefer.
4) Install the classes wherever you prefer.
### Build from Source - With Maven
WARNING: Building from source with Maven is deprecated and will be removed in the 4.28.x release.
1) Install Apache Maven if you don't have it:
http://maven.apache.org/
@ -109,31 +137,6 @@ The above instructions will install 2 maven artifacts:
as well as utilities to work with proto3 well-known
types.
### Build from Source - Without Maven
If you would rather not install Maven to build the library, you may
follow these instructions instead. Note that these instructions skip
running unit tests and only describes how to install the core protobuf
library (without the util package).
1) Build the C++ code, or obtain a binary distribution of protoc. If
you install a binary distribution, make sure that it is the same
version as this package. If in doubt, run:
$ protoc --version
If you built the C++ code without installing, the compiler binary
should be located in ../src.
2) Invoke protoc to build DescriptorProtos.java:
$ protoc --java_out=core/src/main/java -I../src \
../src/google/protobuf/descriptor.proto
3) Compile the code in core/src/main/java using whatever means you prefer.
4) Install the classes wherever you prefer.
## Compatibility Notice
* Protobuf minor version releases are backwards-compatible. If your code

@ -60,6 +60,8 @@ LITE_SRCS = [
"src/main/java/com/google/protobuf/LazyStringArrayList.java",
"src/main/java/com/google/protobuf/LazyStringList.java",
"src/main/java/com/google/protobuf/ListFieldSchema.java",
"src/main/java/com/google/protobuf/ListFieldSchemaLite.java",
"src/main/java/com/google/protobuf/ListFieldSchemas.java",
"src/main/java/com/google/protobuf/LongArrayList.java",
"src/main/java/com/google/protobuf/ManifestSchemaFactory.java",
"src/main/java/com/google/protobuf/MapEntryLite.java",
@ -334,6 +336,7 @@ proto_library(
deps = [
"//:any_proto",
"//:descriptor_proto",
"//:java_features_proto",
"//:lite_test_protos",
"//:wrappers_proto",
"//src/google/protobuf:generic_test_protos",
@ -520,6 +523,7 @@ LITE_TEST_EXCLUSIONS = [
"src/test/java/com/google/protobuf/AnyTest.java",
"src/test/java/com/google/protobuf/CodedInputStreamTest.java",
"src/test/java/com/google/protobuf/DeprecatedFieldTest.java",
"src/test/java/com/google/protobuf/DebugFormatTest.java",
"src/test/java/com/google/protobuf/DescriptorsTest.java",
"src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java",
"src/test/java/com/google/protobuf/DynamicMessageTest.java",

@ -397,6 +397,8 @@ public abstract class AbstractMessageLite<
}
if (value instanceof ByteString) {
lazyList.add((ByteString) value);
} else if (value instanceof byte[]) {
lazyList.add(ByteString.copyFrom((byte[]) value));
} else {
lazyList.add((String) value);
}

@ -2690,6 +2690,9 @@ public abstract class CodedInputStream {
throw InvalidProtocolBufferException.negativeSize();
}
byteLimit += totalBytesRetired + pos;
if (byteLimit < 0) {
throw InvalidProtocolBufferException.parseFailure();
}
final int oldLimit = currentLimit;
if (byteLimit > oldLimit) {
throw InvalidProtocolBufferException.truncatedMessage();

@ -167,6 +167,38 @@ final class CodedOutputStreamWriter implements Writer {
@Override
public void writeInt32List(int fieldNumber, List<Integer> value, boolean packed)
throws IOException {
if (value instanceof IntArrayList) {
writeInt32ListInternal(fieldNumber, (IntArrayList) value, packed);
} else {
writeInt32ListInternal(fieldNumber, value, packed);
}
}
private void writeInt32ListInternal(int fieldNumber, IntArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeInt32SizeNoTag(value.getInt(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeInt32NoTag(value.getInt(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeInt32(fieldNumber, value.getInt(i));
}
}
}
private void writeInt32ListInternal(int fieldNumber, List<Integer> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
@ -191,6 +223,38 @@ final class CodedOutputStreamWriter implements Writer {
@Override
public void writeFixed32List(int fieldNumber, List<Integer> value, boolean packed)
throws IOException {
if (value instanceof IntArrayList) {
writeFixed32ListInternal(fieldNumber, (IntArrayList) value, packed);
} else {
writeFixed32ListInternal(fieldNumber, value, packed);
}
}
private void writeFixed32ListInternal(int fieldNumber, IntArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeFixed32SizeNoTag(value.getInt(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeFixed32NoTag(value.getInt(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeFixed32(fieldNumber, value.getInt(i));
}
}
}
private void writeFixed32ListInternal(int fieldNumber, List<Integer> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
@ -214,6 +278,38 @@ final class CodedOutputStreamWriter implements Writer {
@Override
public void writeInt64List(int fieldNumber, List<Long> value, boolean packed) throws IOException {
if (value instanceof LongArrayList) {
writeInt64ListInternal(fieldNumber, (LongArrayList) value, packed);
} else {
writeInt64ListInternal(fieldNumber, value, packed);
}
}
private void writeInt64ListInternal(int fieldNumber, LongArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeInt64SizeNoTag(value.getLong(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeInt64NoTag(value.getLong(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeInt64(fieldNumber, value.getLong(i));
}
}
}
private void writeInt64ListInternal(int fieldNumber, List<Long> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
@ -234,10 +330,41 @@ final class CodedOutputStreamWriter implements Writer {
}
}
}
@Override
public void writeUInt64List(int fieldNumber, List<Long> value, boolean packed)
throws IOException {
if (value instanceof LongArrayList) {
writeUInt64ListInternal(fieldNumber, (LongArrayList) value, packed);
} else {
writeUInt64ListInternal(fieldNumber, value, packed);
}
}
private void writeUInt64ListInternal(int fieldNumber, LongArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeUInt64SizeNoTag(value.getLong(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeUInt64NoTag(value.getLong(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeUInt64(fieldNumber, value.getLong(i));
}
}
}
private void writeUInt64ListInternal(int fieldNumber, List<Long> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
@ -262,6 +389,38 @@ final class CodedOutputStreamWriter implements Writer {
@Override
public void writeFixed64List(int fieldNumber, List<Long> value, boolean packed)
throws IOException {
if (value instanceof LongArrayList) {
writeFixed64ListInternal(fieldNumber, (LongArrayList) value, packed);
} else {
writeFixed64ListInternal(fieldNumber, value, packed);
}
}
private void writeFixed64ListInternal(int fieldNumber, LongArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeFixed64SizeNoTag(value.getLong(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeFixed64NoTag(value.getLong(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeFixed64(fieldNumber, value.getLong(i));
}
}
}
private void writeFixed64ListInternal(int fieldNumber, List<Long> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
@ -286,6 +445,38 @@ final class CodedOutputStreamWriter implements Writer {
@Override
public void writeFloatList(int fieldNumber, List<Float> value, boolean packed)
throws IOException {
if (value instanceof FloatArrayList) {
writeFloatListInternal(fieldNumber, (FloatArrayList) value, packed);
} else {
writeFloatListInternal(fieldNumber, value, packed);
}
}
private void writeFloatListInternal(int fieldNumber, FloatArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeFloatSizeNoTag(value.getFloat(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeFloatNoTag(value.getFloat(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeFloat(fieldNumber, value.getFloat(i));
}
}
}
private void writeFloatListInternal(int fieldNumber, List<Float> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
@ -310,6 +501,38 @@ final class CodedOutputStreamWriter implements Writer {
@Override
public void writeDoubleList(int fieldNumber, List<Double> value, boolean packed)
throws IOException {
if (value instanceof DoubleArrayList) {
writeDoubleListInternal(fieldNumber, (DoubleArrayList) value, packed);
} else {
writeDoubleListInternal(fieldNumber, value, packed);
}
}
private void writeDoubleListInternal(int fieldNumber, DoubleArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeDoubleSizeNoTag(value.getDouble(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeDoubleNoTag(value.getDouble(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeDouble(fieldNumber, value.getDouble(i));
}
}
}
private void writeDoubleListInternal(int fieldNumber, List<Double> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
@ -334,6 +557,38 @@ final class CodedOutputStreamWriter implements Writer {
@Override
public void writeEnumList(int fieldNumber, List<Integer> value, boolean packed)
throws IOException {
if (value instanceof IntArrayList) {
writeEnumListInternal(fieldNumber, (IntArrayList) value, packed);
} else {
writeEnumListInternal(fieldNumber, value, packed);
}
}
private void writeEnumListInternal(int fieldNumber, IntArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeEnumSizeNoTag(value.getInt(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeEnumNoTag(value.getInt(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeEnum(fieldNumber, value.getInt(i));
}
}
}
private void writeEnumListInternal(int fieldNumber, List<Integer> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
@ -358,6 +613,38 @@ final class CodedOutputStreamWriter implements Writer {
@Override
public void writeBoolList(int fieldNumber, List<Boolean> value, boolean packed)
throws IOException {
if (value instanceof BooleanArrayList) {
writeBoolListInternal(fieldNumber, (BooleanArrayList) value, packed);
} else {
writeBoolListInternal(fieldNumber, value, packed);
}
}
private void writeBoolListInternal(int fieldNumber, BooleanArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeBoolSizeNoTag(value.getBoolean(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeBoolNoTag(value.getBoolean(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeBool(fieldNumber, value.getBoolean(i));
}
}
}
private void writeBoolListInternal(int fieldNumber, List<Boolean> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
@ -411,6 +698,38 @@ final class CodedOutputStreamWriter implements Writer {
@Override
public void writeUInt32List(int fieldNumber, List<Integer> value, boolean packed)
throws IOException {
if (value instanceof IntArrayList) {
writeUInt32ListInternal(fieldNumber, (IntArrayList) value, packed);
} else {
writeUInt32ListInternal(fieldNumber, value, packed);
}
}
private void writeUInt32ListInternal(int fieldNumber, IntArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeUInt32SizeNoTag(value.getInt(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeUInt32NoTag(value.getInt(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeUInt32(fieldNumber, value.getInt(i));
}
}
}
public void writeUInt32ListInternal(int fieldNumber, List<Integer> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
@ -435,6 +754,38 @@ final class CodedOutputStreamWriter implements Writer {
@Override
public void writeSFixed32List(int fieldNumber, List<Integer> value, boolean packed)
throws IOException {
if (value instanceof IntArrayList) {
writeSFixed32ListInternal(fieldNumber, (IntArrayList) value, packed);
} else {
writeSFixed32ListInternal(fieldNumber, value, packed);
}
}
private void writeSFixed32ListInternal(int fieldNumber, IntArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeSFixed32SizeNoTag(value.getInt(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeSFixed32NoTag(value.getInt(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeSFixed32(fieldNumber, value.getInt(i));
}
}
}
private void writeSFixed32ListInternal(int fieldNumber, List<Integer> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
@ -459,6 +810,38 @@ final class CodedOutputStreamWriter implements Writer {
@Override
public void writeSFixed64List(int fieldNumber, List<Long> value, boolean packed)
throws IOException {
if (value instanceof LongArrayList) {
writeSFixed64ListInternal(fieldNumber, (LongArrayList) value, packed);
} else {
writeSFixed64ListInternal(fieldNumber, value, packed);
}
}
private void writeSFixed64ListInternal(int fieldNumber, LongArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeSFixed64SizeNoTag(value.getLong(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeSFixed64NoTag(value.getLong(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeSFixed64(fieldNumber, value.getLong(i));
}
}
}
private void writeSFixed64ListInternal(int fieldNumber, List<Long> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
@ -483,6 +866,38 @@ final class CodedOutputStreamWriter implements Writer {
@Override
public void writeSInt32List(int fieldNumber, List<Integer> value, boolean packed)
throws IOException {
if (value instanceof IntArrayList) {
writeSInt32ListInternal(fieldNumber, (IntArrayList) value, packed);
} else {
writeSInt32ListInternal(fieldNumber, value, packed);
}
}
private void writeSInt32ListInternal(int fieldNumber, IntArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeSInt32SizeNoTag(value.getInt(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeSInt32NoTag(value.getInt(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeSInt32(fieldNumber, value.getInt(i));
}
}
}
public void writeSInt32ListInternal(int fieldNumber, List<Integer> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
@ -507,6 +922,38 @@ final class CodedOutputStreamWriter implements Writer {
@Override
public void writeSInt64List(int fieldNumber, List<Long> value, boolean packed)
throws IOException {
if (value instanceof LongArrayList) {
writeSInt64ListInternal(fieldNumber, (LongArrayList) value, packed);
} else {
writeSInt64ListInternal(fieldNumber, value, packed);
}
}
private void writeSInt64ListInternal(int fieldNumber, LongArrayList value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
// Compute and write the length of the data.
int dataSize = 0;
for (int i = 0; i < value.size(); ++i) {
dataSize += CodedOutputStream.computeSInt64SizeNoTag(value.getLong(i));
}
output.writeUInt32NoTag(dataSize);
// Write the data itself, without any tags.
for (int i = 0; i < value.size(); ++i) {
output.writeSInt64NoTag(value.getLong(i));
}
} else {
for (int i = 0; i < value.size(); ++i) {
output.writeSInt64(fieldNumber, value.getLong(i));
}
}
}
private void writeSInt64ListInternal(int fieldNumber, List<Long> value, boolean packed)
throws IOException {
if (packed) {
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);

@ -0,0 +1,79 @@
package com.google.protobuf;
import com.google.protobuf.Descriptors.FieldDescriptor;
/**
* Provides an explicit API for unstable, redacting debug output suitable for debug logging. This
* implementation is based on TextFormat, but should not be parsed.
*/
public final class DebugFormat {
private final boolean isSingleLine;
private DebugFormat(boolean singleLine) {
isSingleLine = singleLine;
}
public static DebugFormat singleLine() {
return new DebugFormat(true);
}
public static DebugFormat multiline() {
return new DebugFormat(false);
}
public String toString(MessageOrBuilder message) {
return TextFormat.printer()
.emittingSingleLine(this.isSingleLine)
.enablingSafeDebugFormat(true)
.printToString(message);
}
public String toString(FieldDescriptor field, Object value) {
return TextFormat.printer()
.emittingSingleLine(this.isSingleLine)
.enablingSafeDebugFormat(true)
.printFieldToString(field, value);
}
public String toString(UnknownFieldSet fields) {
return TextFormat.printer()
.emittingSingleLine(this.isSingleLine)
.enablingSafeDebugFormat(true)
.printToString(fields);
}
public Object lazyToString(MessageOrBuilder message) {
return new LazyDebugOutput(message, this);
}
public Object lazyToString(UnknownFieldSet fields) {
return new LazyDebugOutput(fields, this);
}
private static class LazyDebugOutput {
private final MessageOrBuilder message;
private final UnknownFieldSet fields;
private final DebugFormat format;
LazyDebugOutput(MessageOrBuilder message, DebugFormat format) {
this.message = message;
this.fields = null;
this.format = format;
}
LazyDebugOutput(UnknownFieldSet fields, DebugFormat format) {
this.message = null;
this.fields = fields;
this.format = format;
}
@Override
public String toString() {
if (message != null) {
return format.toString(message);
}
return format.toString(fields);
}
}
}

@ -94,7 +94,7 @@ public final class Descriptors {
if (javaEditionDefaults == null) {
try {
ExtensionRegistry registry = ExtensionRegistry.newInstance();
registry.add(JavaFeaturesProto.java);
registry.add(JavaFeaturesProto.java_);
setTestJavaEditionDefaults(
FeatureSetDefaults.parseFrom(
JavaEditionDefaults.PROTOBUF_INTERNAL_JAVA_EDITION_DEFAULTS.getBytes(
@ -679,7 +679,7 @@ public final class Descriptors {
if (getEdition() == Edition.EDITION_PROTO2) {
if (proto.getOptions().getJavaStringCheckUtf8()) {
features.setExtension(
JavaFeaturesProto.java,
JavaFeaturesProto.java_,
JavaFeatures.newBuilder()
.setUtf8Validation(JavaFeatures.Utf8Validation.VERIFY)
.build());
@ -1320,7 +1320,7 @@ public final class Descriptors {
return true;
}
if (this.features
.getExtension(JavaFeaturesProto.java)
.getExtension(JavaFeaturesProto.java_)
.getUtf8Validation()
.equals(JavaFeatures.Utf8Validation.VERIFY)) {
return true;
@ -1577,7 +1577,7 @@ public final class Descriptors {
}
return getType() == Type.ENUM
&& (this.features.getExtension(JavaFeaturesProto.java).getLegacyClosedEnum()
&& (this.features.getExtension(JavaFeaturesProto.java_).getLegacyClosedEnum()
|| enumType.isClosed());
}

@ -31,4 +31,6 @@ final class ExtensionSchemas {
}
return FULL_SCHEMA;
}
private ExtensionSchemas() {}
}

@ -1621,10 +1621,17 @@ public abstract class GeneratedMessageLite<
/** A static helper method for parsing a partial from byte array. */
private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
T instance, byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry)
T defaultInstance,
byte[] input,
int offset,
int length,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
if (length == 0) {
return defaultInstance;
}
@SuppressWarnings("unchecked") // Guaranteed by protoc
T result = instance.newMutableInstance();
T result = defaultInstance.newMutableInstance();
try {
Schema<T> schema = Protobuf.getInstance().schemaFor(result);
schema.mergeFrom(

@ -47,7 +47,7 @@ final class IntArrayList extends AbstractProtobufList<Integer>
*/
private IntArrayList(int[] other, int size, boolean isMutable) {
super(isMutable);
array = other;
this.array = other;
this.size = size;
}

@ -371,6 +371,36 @@ public final class Internal {
return ((MessageLite) destination).toBuilder().mergeFrom((MessageLite) source).buildPartial();
}
/**
* Provides an immutable view of {@code List<T>} around an {@code IntList}.
*
* <p>Protobuf internal. Used in protobuf generated code only.
*/
public static class IntListAdapter<T> extends AbstractList<T> {
/** Convert individual elements of the List from int to T. */
public interface IntConverter<T> {
T convert(int from);
}
private final IntList fromList;
private final IntConverter<T> converter;
public IntListAdapter(IntList fromList, IntConverter<T> converter) {
this.fromList = fromList;
this.converter = converter;
}
@Override
public T get(int index) {
return converter.convert(fromList.getInt(index));
}
@Override
public int size() {
return fromList.size();
}
}
/**
* Provides an immutable view of {@code List<T>} around a {@code List<F>}.
*

@ -7,162 +7,17 @@
package com.google.protobuf;
import com.google.protobuf.Internal.ProtobufList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Utility class that aids in properly manipulating list fields for either the lite or full runtime.
*/
@CheckReturnValue
abstract class ListFieldSchema {
// Disallow construction.
private ListFieldSchema() {}
interface ListFieldSchema {
private static final ListFieldSchema FULL_INSTANCE = new ListFieldSchemaFull();
private static final ListFieldSchema LITE_INSTANCE = new ListFieldSchemaLite();
<L> List<L> mutableListAt(Object msg, long offset);
abstract <L> List<L> mutableListAt(Object msg, long offset);
void makeImmutableListAt(Object msg, long offset);
abstract void makeImmutableListAt(Object msg, long offset);
abstract <L> void mergeListsAt(Object msg, Object otherMsg, long offset);
static ListFieldSchema full() {
return FULL_INSTANCE;
}
static ListFieldSchema lite() {
return LITE_INSTANCE;
}
/** Implementation for the full runtime. */
private static final class ListFieldSchemaFull extends ListFieldSchema {
private static final Class<?> UNMODIFIABLE_LIST_CLASS =
Collections.unmodifiableList(Collections.emptyList()).getClass();
@Override
<L> List<L> mutableListAt(Object message, long offset) {
return mutableListAt(message, offset, AbstractProtobufList.DEFAULT_CAPACITY);
}
@Override
void makeImmutableListAt(Object message, long offset) {
List<?> list = (List<?>) UnsafeUtil.getObject(message, offset);
Object immutable = null;
if (list instanceof LazyStringList) {
immutable = ((LazyStringList) list).getUnmodifiableView();
} else if (UNMODIFIABLE_LIST_CLASS.isAssignableFrom(list.getClass())) {
// already immutable
return;
} else if (list instanceof PrimitiveNonBoxingCollection && list instanceof ProtobufList) {
if (((ProtobufList<?>) list).isModifiable()) {
((ProtobufList<?>) list).makeImmutable();
}
return;
} else {
immutable = Collections.unmodifiableList((List<?>) list);
}
UnsafeUtil.putObject(message, offset, immutable);
}
@SuppressWarnings("unchecked")
private static <L> List<L> mutableListAt(Object message, long offset, int additionalCapacity) {
List<L> list = getList(message, offset);
if (list.isEmpty()) {
if (list instanceof LazyStringList) {
list = (List<L>) new LazyStringArrayList(additionalCapacity);
} else if (list instanceof PrimitiveNonBoxingCollection && list instanceof ProtobufList) {
list = ((ProtobufList<L>) list).mutableCopyWithCapacity(additionalCapacity);
} else {
list = new ArrayList<L>(additionalCapacity);
}
UnsafeUtil.putObject(message, offset, list);
} else if (UNMODIFIABLE_LIST_CLASS.isAssignableFrom(list.getClass())) {
ArrayList<L> newList = new ArrayList<L>(list.size() + additionalCapacity);
newList.addAll(list);
list = newList;
UnsafeUtil.putObject(message, offset, list);
} else if (list instanceof UnmodifiableLazyStringList) {
LazyStringArrayList newList = new LazyStringArrayList(list.size() + additionalCapacity);
newList.addAll((UnmodifiableLazyStringList) list);
list = (List<L>) newList;
UnsafeUtil.putObject(message, offset, list);
} else if (list instanceof PrimitiveNonBoxingCollection
&& list instanceof ProtobufList
&& !((ProtobufList<L>) list).isModifiable()) {
list = ((ProtobufList<L>) list).mutableCopyWithCapacity(list.size() + additionalCapacity);
UnsafeUtil.putObject(message, offset, list);
}
return list;
}
@Override
<E> void mergeListsAt(Object msg, Object otherMsg, long offset) {
List<E> other = getList(otherMsg, offset);
List<E> mine = mutableListAt(msg, offset, other.size());
int size = mine.size();
int otherSize = other.size();
if (size > 0 && otherSize > 0) {
mine.addAll(other);
}
List<E> merged = size > 0 ? mine : other;
UnsafeUtil.putObject(msg, offset, merged);
}
@SuppressWarnings("unchecked")
static <E> List<E> getList(Object message, long offset) {
return (List<E>) UnsafeUtil.getObject(message, offset);
}
}
/** Implementation for the lite runtime. */
private static final class ListFieldSchemaLite extends ListFieldSchema {
@Override
<L> List<L> mutableListAt(Object message, long offset) {
ProtobufList<L> list = getProtobufList(message, offset);
if (!list.isModifiable()) {
int size = list.size();
list =
list.mutableCopyWithCapacity(
size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
UnsafeUtil.putObject(message, offset, list);
}
return list;
}
@Override
void makeImmutableListAt(Object message, long offset) {
ProtobufList<?> list = getProtobufList(message, offset);
list.makeImmutable();
}
@Override
<E> void mergeListsAt(Object msg, Object otherMsg, long offset) {
ProtobufList<E> mine = getProtobufList(msg, offset);
ProtobufList<E> other = getProtobufList(otherMsg, offset);
int size = mine.size();
int otherSize = other.size();
if (size > 0 && otherSize > 0) {
if (!mine.isModifiable()) {
mine = mine.mutableCopyWithCapacity(size + otherSize);
}
mine.addAll(other);
}
ProtobufList<E> merged = size > 0 ? mine : other;
UnsafeUtil.putObject(msg, offset, merged);
}
@SuppressWarnings("unchecked")
static <E> ProtobufList<E> getProtobufList(Object message, long offset) {
return (ProtobufList<E>) UnsafeUtil.getObject(message, offset);
}
}
<L> void mergeListsAt(Object msg, Object otherMsg, long offset);
}

@ -0,0 +1,99 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
package com.google.protobuf;
import com.google.protobuf.Internal.ProtobufList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Utility class that aids in properly manipulating list fields for either the lite or full runtime.
*/
@CheckReturnValue
final class ListFieldSchemaFull implements ListFieldSchema {
private static final Class<?> UNMODIFIABLE_LIST_CLASS =
Collections.unmodifiableList(Collections.emptyList()).getClass();
@Override
public <L> List<L> mutableListAt(Object message, long offset) {
return mutableListAt(message, offset, AbstractProtobufList.DEFAULT_CAPACITY);
}
@SuppressWarnings("unchecked")
private static <L> List<L> mutableListAt(Object message, long offset, int additionalCapacity) {
List<L> list = getList(message, offset);
if (list.isEmpty()) {
if (list instanceof LazyStringList) {
list = (List<L>) new LazyStringArrayList(additionalCapacity);
} else if (list instanceof PrimitiveNonBoxingCollection && list instanceof ProtobufList) {
list = ((ProtobufList<L>) list).mutableCopyWithCapacity(additionalCapacity);
} else {
list = new ArrayList<L>(additionalCapacity);
}
UnsafeUtil.putObject(message, offset, list);
} else if (UNMODIFIABLE_LIST_CLASS.isAssignableFrom(list.getClass())) {
ArrayList<L> newList = new ArrayList<L>(list.size() + additionalCapacity);
newList.addAll(list);
list = newList;
UnsafeUtil.putObject(message, offset, list);
} else if (list instanceof UnmodifiableLazyStringList) {
LazyStringArrayList newList = new LazyStringArrayList(list.size() + additionalCapacity);
newList.addAll((UnmodifiableLazyStringList) list);
list = (List<L>) newList;
UnsafeUtil.putObject(message, offset, list);
} else if (list instanceof PrimitiveNonBoxingCollection
&& list instanceof ProtobufList
&& !((ProtobufList<L>) list).isModifiable()) {
list = ((ProtobufList<L>) list).mutableCopyWithCapacity(list.size() + additionalCapacity);
UnsafeUtil.putObject(message, offset, list);
}
return list;
}
@Override
public void makeImmutableListAt(Object message, long offset) {
List<?> list = (List<?>) UnsafeUtil.getObject(message, offset);
Object immutable = null;
if (list instanceof LazyStringList) {
immutable = ((LazyStringList) list).getUnmodifiableView();
} else if (UNMODIFIABLE_LIST_CLASS.isAssignableFrom(list.getClass())) {
// already immutable
return;
} else if (list instanceof PrimitiveNonBoxingCollection && list instanceof ProtobufList) {
if (((ProtobufList<?>) list).isModifiable()) {
((ProtobufList<?>) list).makeImmutable();
}
return;
} else {
immutable = Collections.unmodifiableList((List<?>) list);
}
UnsafeUtil.putObject(message, offset, immutable);
}
@Override
public <E> void mergeListsAt(Object msg, Object otherMsg, long offset) {
List<E> other = getList(otherMsg, offset);
List<E> mine = mutableListAt(msg, offset, other.size());
int size = mine.size();
int otherSize = other.size();
if (size > 0 && otherSize > 0) {
mine.addAll(other);
}
List<E> merged = size > 0 ? mine : other;
UnsafeUtil.putObject(msg, offset, merged);
}
@SuppressWarnings("unchecked")
static <E> List<E> getList(Object message, long offset) {
return (List<E>) UnsafeUtil.getObject(message, offset);
}
}

@ -0,0 +1,59 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
package com.google.protobuf;
import com.google.protobuf.Internal.ProtobufList;
import java.util.List;
/**
* Utility class that aids in properly manipulating list fields for either the lite or full runtime.
*/
final class ListFieldSchemaLite implements ListFieldSchema {
@Override
public <L> List<L> mutableListAt(Object message, long offset) {
ProtobufList<L> list = getProtobufList(message, offset);
if (!list.isModifiable()) {
int size = list.size();
list =
list.mutableCopyWithCapacity(
size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
UnsafeUtil.putObject(message, offset, list);
}
return list;
}
@Override
public void makeImmutableListAt(Object message, long offset) {
ProtobufList<?> list = getProtobufList(message, offset);
list.makeImmutable();
}
@Override
public <E> void mergeListsAt(Object msg, Object otherMsg, long offset) {
ProtobufList<E> mine = getProtobufList(msg, offset);
ProtobufList<E> other = getProtobufList(otherMsg, offset);
int size = mine.size();
int otherSize = other.size();
if (size > 0 && otherSize > 0) {
if (!mine.isModifiable()) {
mine = mine.mutableCopyWithCapacity(size + otherSize);
}
mine.addAll(other);
}
ProtobufList<E> merged = size > 0 ? mine : other;
UnsafeUtil.putObject(msg, offset, merged);
}
@SuppressWarnings("unchecked")
static <E> ProtobufList<E> getProtobufList(Object message, long offset) {
return (ProtobufList<E>) UnsafeUtil.getObject(message, offset);
}
}

@ -0,0 +1,33 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
package com.google.protobuf;
@CheckReturnValue
final class ListFieldSchemas {
private static final ListFieldSchema FULL_SCHEMA = loadSchemaForFullRuntime();
private static final ListFieldSchema LITE_SCHEMA = new ListFieldSchemaLite();
static ListFieldSchema full() {
return FULL_SCHEMA;
}
static ListFieldSchema lite() {
return LITE_SCHEMA;
}
private static ListFieldSchema loadSchemaForFullRuntime() {
try {
Class<?> clazz = Class.forName("com.google.protobuf.ListFieldSchemaFull");
return (ListFieldSchema) clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
return null;
}
}
private ListFieldSchemas() {}
}

@ -34,57 +34,37 @@ final class ManifestSchemaFactory implements SchemaFactory {
// MessageSet has a special schema.
if (messageInfo.isMessageSetWireFormat()) {
if (GeneratedMessageLite.class.isAssignableFrom(messageType)) {
return MessageSetSchema.newSchema(
SchemaUtil.unknownFieldSetLiteSchema(),
ExtensionSchemas.lite(),
messageInfo.getDefaultInstance());
}
return MessageSetSchema.newSchema(
SchemaUtil.unknownFieldSetFullSchema(),
ExtensionSchemas.full(),
messageInfo.getDefaultInstance());
return useLiteRuntime(messageType)
? MessageSetSchema.newSchema(
SchemaUtil.unknownFieldSetLiteSchema(),
ExtensionSchemas.lite(),
messageInfo.getDefaultInstance())
: MessageSetSchema.newSchema(
SchemaUtil.unknownFieldSetFullSchema(),
ExtensionSchemas.full(),
messageInfo.getDefaultInstance());
}
return newSchema(messageType, messageInfo);
}
private static <T> Schema<T> newSchema(Class<T> messageType, MessageInfo messageInfo) {
if (GeneratedMessageLite.class.isAssignableFrom(messageType)) {
return allowExtensions(messageInfo)
? MessageSchema.newSchema(
messageType,
messageInfo,
NewInstanceSchemas.lite(),
ListFieldSchema.lite(),
SchemaUtil.unknownFieldSetLiteSchema(),
ExtensionSchemas.lite(),
MapFieldSchemas.lite())
: MessageSchema.newSchema(
messageType,
messageInfo,
NewInstanceSchemas.lite(),
ListFieldSchema.lite(),
SchemaUtil.unknownFieldSetLiteSchema(),
/* extensionSchema= */ null,
MapFieldSchemas.lite());
}
return allowExtensions(messageInfo)
return useLiteRuntime(messageType)
? MessageSchema.newSchema(
messageType,
messageInfo,
NewInstanceSchemas.full(),
ListFieldSchema.full(),
SchemaUtil.unknownFieldSetFullSchema(),
ExtensionSchemas.full(),
MapFieldSchemas.full())
NewInstanceSchemas.lite(),
ListFieldSchemas.lite(),
SchemaUtil.unknownFieldSetLiteSchema(),
allowExtensions(messageInfo) ? ExtensionSchemas.lite() : null,
MapFieldSchemas.lite())
: MessageSchema.newSchema(
messageType,
messageInfo,
NewInstanceSchemas.full(),
ListFieldSchema.full(),
ListFieldSchemas.full(),
SchemaUtil.unknownFieldSetFullSchema(),
/* extensionSchema= */ null,
allowExtensions(messageInfo) ? ExtensionSchemas.full() : null,
MapFieldSchemas.full());
}
@ -152,4 +132,8 @@ final class ManifestSchemaFactory implements SchemaFactory {
return EMPTY_FACTORY;
}
}
private static boolean useLiteRuntime(Class<?> messageType) {
return GeneratedMessageLite.class.isAssignableFrom(messageType);
}
}

@ -10,7 +10,7 @@ package com.google.protobuf;
import com.google.protobuf.MapEntryLite.Metadata;
import java.util.Map;
class MapFieldSchemaFull implements MapFieldSchema {
final class MapFieldSchemaFull implements MapFieldSchema {
@Override
public Map<?, ?> forMutableMapData(Object mapField) {
return ((MapField<?, ?>) mapField).getMutableMap();

@ -11,7 +11,7 @@ import com.google.protobuf.MapEntryLite.Metadata;
import java.util.Map;
@CheckReturnValue
class MapFieldSchemaLite implements MapFieldSchema {
final class MapFieldSchemaLite implements MapFieldSchema {
@Override
public Map<?, ?> forMutableMapData(Object mapField) {

@ -28,4 +28,6 @@ final class MapFieldSchemas {
return null;
}
}
private MapFieldSchemas() {}
}

@ -28,4 +28,6 @@ final class NewInstanceSchemas {
return null;
}
}
private NewInstanceSchemas() {}
}

@ -24,12 +24,18 @@ public final class RuntimeVersion {
// The version of this runtime.
// Automatically updated by Protobuf release process. Do not edit manually.
public static final RuntimeDomain DOMAIN = RuntimeDomain.PUBLIC;
public static final int MAJOR = 4;
public static final int MINOR = 28;
public static final int PATCH = 0;
public static final String SUFFIX = "-dev";
// These OSS versions are not stripped to avoid merging conflicts.
public static final RuntimeDomain OSS_DOMAIN = RuntimeDomain.PUBLIC;
public static final int OSS_MAJOR = 4;
public static final int OSS_MINOR = 28;
public static final int OSS_PATCH = 0;
public static final String OSS_SUFFIX = "-dev";
public static final RuntimeDomain DOMAIN = OSS_DOMAIN;
public static final int MAJOR = OSS_MAJOR;
public static final int MINOR = OSS_MINOR;
public static final int PATCH = OSS_PATCH;
public static final String SUFFIX = OSS_SUFFIX;
private static final String VERSION_STRING = versionString(MAJOR, MINOR, PATCH, SUFFIX);
private static final Logger logger = Logger.getLogger(RuntimeVersion.class.getName());
@ -88,7 +94,7 @@ public final class RuntimeVersion {
}
// Check that runtime version is newer than the gencode version.
if (MINOR < minor || (MINOR == minor && PATCH < patch)) {
if (MINOR < minor || (minor == MINOR && PATCH < patch)) {
throw new ProtobufRuntimeVersionException(
String.format(
"Detected incompatible Protobuf Gencode/Runtime versions when loading %s: gencode %s,"

@ -14,7 +14,6 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
@ -169,13 +168,13 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
/** @return An iterable over the overflow entries. */
public Iterable<Map.Entry<K, V>> getOverflowEntries() {
return overflowEntries.isEmpty()
? EmptySet.<Map.Entry<K, V>>iterable()
? Collections.emptySet()
: overflowEntries.entrySet();
}
Iterable<Map.Entry<K, V>> getOverflowEntriesDescending() {
return overflowEntriesDescending.isEmpty()
? EmptySet.<Map.Entry<K, V>>iterable()
? Collections.emptySet()
: overflowEntriesDescending.entrySet();
}
@ -597,45 +596,6 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
}
}
/**
* Helper class that holds immutable instances of an Iterable/Iterator that we return when the
* overflow entries is empty. This eliminates the creation of an Iterator object when there is
* nothing to iterate over.
*/
private static class EmptySet {
private static final Iterator<Object> ITERATOR =
new Iterator<Object>() {
@Override
public boolean hasNext() {
return false;
}
@Override
public Object next() {
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
private static final Iterable<Object> ITERABLE =
new Iterable<Object>() {
@Override
public Iterator<Object> iterator() {
return ITERATOR;
}
};
@SuppressWarnings("unchecked")
static <T> Iterable<T> iterable() {
return (Iterable<T>) ITERABLE;
}
}
@Override
public boolean equals(Object o) {
if (this == o) {

@ -38,6 +38,8 @@ public final class TextFormat {
private static final String DEBUG_STRING_SILENT_MARKER = "\t ";
private static final String REDACTED_MARKER = "[REDACTED]";
/**
* Generates a human readable form of this message, useful for debugging and other purposes, with
* no newline characters. This is just a trivial wrapper around {@link
@ -58,11 +60,12 @@ public final class TextFormat {
*/
public static void printUnknownFieldValue(
final int tag, final Object value, final Appendable output) throws IOException {
printUnknownFieldValue(tag, value, multiLineOutput(output));
printUnknownFieldValue(tag, value, setSingleLineOutput(output, false), false);
}
private static void printUnknownFieldValue(
final int tag, final Object value, final TextGenerator generator) throws IOException {
final int tag, final Object value, final TextGenerator generator, boolean redact)
throws IOException {
switch (WireFormat.getTagWireType(tag)) {
case WireFormat.WIRETYPE_VARINT:
generator.print(unsignedToString((Long) value));
@ -80,7 +83,7 @@ public final class TextFormat {
generator.print("{");
generator.eol();
generator.indent();
Printer.printUnknownFields(message, generator);
Printer.printUnknownFields(message, generator, redact);
generator.outdent();
generator.print("}");
} catch (InvalidProtocolBufferException e) {
@ -91,7 +94,7 @@ public final class TextFormat {
}
break;
case WireFormat.WIRETYPE_START_GROUP:
Printer.printUnknownFields((UnknownFieldSet) value, generator);
Printer.printUnknownFields((UnknownFieldSet) value, generator, redact);
break;
default:
throw new IllegalArgumentException("Bad tag: " + tag);
@ -109,7 +112,11 @@ public final class TextFormat {
// Printer instance which escapes non-ASCII characters.
private static final Printer DEFAULT =
new Printer(
true, TypeRegistry.getEmptyTypeRegistry(), ExtensionRegistryLite.getEmptyRegistry());
true,
TypeRegistry.getEmptyTypeRegistry(),
ExtensionRegistryLite.getEmptyRegistry(),
false,
false);
/** Whether to escape non ASCII characters with backslash and octal. */
private final boolean escapeNonAscii;
@ -117,13 +124,25 @@ public final class TextFormat {
private final TypeRegistry typeRegistry;
private final ExtensionRegistryLite extensionRegistry;
/**
* Whether to enable redaction of sensitive fields and introduce randomization. Note that when
* this is enabled, the output will no longer be deserializable.
*/
private final boolean enablingSafeDebugFormat;
private final boolean singleLine;
private Printer(
boolean escapeNonAscii,
TypeRegistry typeRegistry,
ExtensionRegistryLite extensionRegistry) {
ExtensionRegistryLite extensionRegistry,
boolean enablingSafeDebugFormat,
boolean singleLine) {
this.escapeNonAscii = escapeNonAscii;
this.typeRegistry = typeRegistry;
this.extensionRegistry = extensionRegistry;
this.enablingSafeDebugFormat = enablingSafeDebugFormat;
this.singleLine = singleLine;
}
/**
@ -136,7 +155,8 @@ public final class TextFormat {
* with the escape mode set to the given parameter.
*/
public Printer escapingNonAscii(boolean escapeNonAscii) {
return new Printer(escapeNonAscii, typeRegistry, extensionRegistry);
return new Printer(
escapeNonAscii, typeRegistry, extensionRegistry, enablingSafeDebugFormat, singleLine);
}
/**
@ -149,7 +169,8 @@ public final class TextFormat {
if (this.typeRegistry != TypeRegistry.getEmptyTypeRegistry()) {
throw new IllegalArgumentException("Only one typeRegistry is allowed.");
}
return new Printer(escapeNonAscii, typeRegistry, extensionRegistry);
return new Printer(
escapeNonAscii, typeRegistry, extensionRegistry, enablingSafeDebugFormat, singleLine);
}
/**
@ -162,7 +183,34 @@ public final class TextFormat {
if (this.extensionRegistry != ExtensionRegistryLite.getEmptyRegistry()) {
throw new IllegalArgumentException("Only one extensionRegistry is allowed.");
}
return new Printer(escapeNonAscii, typeRegistry, extensionRegistry);
return new Printer(
escapeNonAscii, typeRegistry, extensionRegistry, enablingSafeDebugFormat, singleLine);
}
/**
* Return a new Printer instance that outputs a redacted and unstable format suitable for
* debugging.
*
* @param enablingSafeDebugFormat If true, the new Printer will redact all proto fields that are
* marked by a debug_redact=true option, and apply an unstable prefix to the output.
* @return a new Printer that clones all other configurations from the current {@link Printer},
* with the enablingSafeDebugFormat mode set to the given parameter.
*/
Printer enablingSafeDebugFormat(boolean enablingSafeDebugFormat) {
return new Printer(
escapeNonAscii, typeRegistry, extensionRegistry, enablingSafeDebugFormat, singleLine);
}
/**
* Return a new Printer instance with the specified line formatting status.
*
* @param singleLine If true, the new Printer will output no newline characters.
* @return a new Printer that clones all other configurations from the current {@link Printer},
* with the singleLine mode set to the given parameter.
*/
public Printer emittingSingleLine(boolean singleLine) {
return new Printer(
escapeNonAscii, typeRegistry, extensionRegistry, enablingSafeDebugFormat, singleLine);
}
/**
@ -171,12 +219,13 @@ public final class TextFormat {
* original Protocol Buffer system)
*/
public void print(final MessageOrBuilder message, final Appendable output) throws IOException {
print(message, multiLineOutput(output));
print(message, setSingleLineOutput(output, this.singleLine));
}
/** Outputs a textual representation of {@code fields} to {@code output}. */
public void print(final UnknownFieldSet fields, final Appendable output) throws IOException {
printUnknownFields(fields, multiLineOutput(output));
printUnknownFields(
fields, setSingleLineOutput(output, this.singleLine), this.enablingSafeDebugFormat);
}
private void print(final MessageOrBuilder message, final TextGenerator generator)
@ -188,6 +237,14 @@ public final class TextFormat {
printMessage(message, generator);
}
private void applyUnstablePrefix(final Appendable output) {
try {
output.append("");
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
/**
* Attempt to print the 'google.protobuf.Any' message in a human-friendly format. Returns false
* if the message isn't a valid 'google.protobuf.Any' message (in which case the message should
@ -244,6 +301,9 @@ public final class TextFormat {
public String printFieldToString(final FieldDescriptor field, final Object value) {
try {
final StringBuilder text = new StringBuilder();
if (enablingSafeDebugFormat) {
applyUnstablePrefix(text);
}
printField(field, value, text);
return text.toString();
} catch (IOException e) {
@ -253,7 +313,7 @@ public final class TextFormat {
public void printField(final FieldDescriptor field, final Object value, final Appendable output)
throws IOException {
printField(field, value, multiLineOutput(output));
printField(field, value, setSingleLineOutput(output, this.singleLine));
}
private void printField(
@ -358,12 +418,19 @@ public final class TextFormat {
public void printFieldValue(
final FieldDescriptor field, final Object value, final Appendable output)
throws IOException {
printFieldValue(field, value, multiLineOutput(output));
printFieldValue(field, value, setSingleLineOutput(output, this.singleLine));
}
private void printFieldValue(
final FieldDescriptor field, final Object value, final TextGenerator generator)
throws IOException {
if (shouldRedact(field)) {
generator.print(REDACTED_MARKER);
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
generator.eol();
}
return;
}
switch (field.getType()) {
case INT32:
case SINT32:
@ -429,10 +496,54 @@ public final class TextFormat {
}
}
private boolean shouldRedactOptionValue(EnumValueDescriptor optionValue) {
if (optionValue.getOptions().hasDebugRedact()) {
return optionValue.getOptions().getDebugRedact();
}
return false;
}
// The criteria for redacting a field is as follows: 1) The enablingSafeDebugFormat printer
// option
// must be on. 2) The field must be marked by a debug_redact=true option, or is marked by an
// option with an enum value that is marked by a debug_redact=true option.
private boolean shouldRedact(final FieldDescriptor field) {
if (!this.enablingSafeDebugFormat) {
return false;
}
if (field.getOptions().hasDebugRedact()) {
return field.getOptions().getDebugRedact();
}
// Iterate through every option; if it's an enum, we check each enum value for debug_redact.
for (Map.Entry<Descriptors.FieldDescriptor, Object> entry :
field.getOptions().getAllFields().entrySet()) {
Descriptors.FieldDescriptor option = entry.getKey();
if (option.getType() != Descriptors.FieldDescriptor.Type.ENUM) {
continue;
}
if (option.isRepeated()) {
for (EnumValueDescriptor value : (List<EnumValueDescriptor>) entry.getValue()) {
if (shouldRedactOptionValue(value)) {
return true;
}
}
} else {
EnumValueDescriptor optionValue = (EnumValueDescriptor) entry.getValue();
if (shouldRedactOptionValue(optionValue)) {
return true;
}
}
}
return false;
}
/** Like {@code print()}, but writes directly to a {@code String} and returns it. */
public String printToString(final MessageOrBuilder message) {
try {
final StringBuilder text = new StringBuilder();
if (enablingSafeDebugFormat) {
applyUnstablePrefix(text);
}
print(message, text);
return text.toString();
} catch (IOException e) {
@ -443,6 +554,9 @@ public final class TextFormat {
public String printToString(final UnknownFieldSet fields) {
try {
final StringBuilder text = new StringBuilder();
if (enablingSafeDebugFormat) {
applyUnstablePrefix(text);
}
print(fields, text);
return text.toString();
} catch (IOException e) {
@ -457,7 +571,7 @@ public final class TextFormat {
public String shortDebugString(final MessageOrBuilder message) {
try {
final StringBuilder text = new StringBuilder();
print(message, singleLineOutput(text));
print(message, setSingleLineOutput(text, true));
return text.toString();
} catch (IOException e) {
throw new IllegalStateException(e);
@ -471,7 +585,7 @@ public final class TextFormat {
public String shortDebugString(final FieldDescriptor field, final Object value) {
try {
final StringBuilder text = new StringBuilder();
printField(field, value, singleLineOutput(text));
printField(field, value, setSingleLineOutput(text, true));
return text.toString();
} catch (IOException e) {
throw new IllegalStateException(e);
@ -485,7 +599,7 @@ public final class TextFormat {
public String shortDebugString(final UnknownFieldSet fields) {
try {
final StringBuilder text = new StringBuilder();
printUnknownFields(fields, singleLineOutput(text));
printUnknownFields(fields, setSingleLineOutput(text, true), this.enablingSafeDebugFormat);
return text.toString();
} catch (IOException e) {
throw new IllegalStateException(e);
@ -493,16 +607,26 @@ public final class TextFormat {
}
private static void printUnknownFieldValue(
final int tag, final Object value, final TextGenerator generator) throws IOException {
final int tag, final Object value, final TextGenerator generator, boolean redact)
throws IOException {
switch (WireFormat.getTagWireType(tag)) {
case WireFormat.WIRETYPE_VARINT:
generator.print(unsignedToString((Long) value));
generator.print(
redact
? String.format("UNKNOWN_VARINT %s", REDACTED_MARKER)
: unsignedToString((Long) value));
break;
case WireFormat.WIRETYPE_FIXED32:
generator.print(String.format((Locale) null, "0x%08x", (Integer) value));
generator.print(
redact
? String.format("UNKNOWN_FIXED32 %s", REDACTED_MARKER)
: String.format((Locale) null, "0x%08x", (Integer) value));
break;
case WireFormat.WIRETYPE_FIXED64:
generator.print(String.format((Locale) null, "0x%016x", (Long) value));
generator.print(
redact
? String.format("UNKNOWN_FIXED64 %s", REDACTED_MARKER)
: String.format((Locale) null, "0x%016x", (Long) value));
break;
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
try {
@ -511,18 +635,22 @@ public final class TextFormat {
generator.print("{");
generator.eol();
generator.indent();
printUnknownFields(message, generator);
printUnknownFields(message, generator, redact);
generator.outdent();
generator.print("}");
} catch (InvalidProtocolBufferException e) {
// If not parseable as a message, print as a String
if (redact) {
generator.print(String.format("UNKNOWN_STRING %s", REDACTED_MARKER));
break;
}
generator.print("\"");
generator.print(escapeBytes((ByteString) value));
generator.print("\"");
}
break;
case WireFormat.WIRETYPE_START_GROUP:
printUnknownFields((UnknownFieldSet) value, generator);
printUnknownFields((UnknownFieldSet) value, generator, redact);
break;
default:
throw new IllegalArgumentException("Bad tag: " + tag);
@ -534,7 +662,7 @@ public final class TextFormat {
for (Map.Entry<FieldDescriptor, Object> field : message.getAllFields().entrySet()) {
printField(field.getKey(), field.getValue(), generator);
}
printUnknownFields(message.getUnknownFields(), generator);
printUnknownFields(message.getUnknownFields(), generator, this.enablingSafeDebugFormat);
}
private void printSingleField(
@ -580,24 +708,32 @@ public final class TextFormat {
}
private static void printUnknownFields(
final UnknownFieldSet unknownFields, final TextGenerator generator) throws IOException {
final UnknownFieldSet unknownFields, final TextGenerator generator, boolean redact)
throws IOException {
if (unknownFields.isEmpty()) {
return;
}
for (Map.Entry<Integer, UnknownFieldSet.Field> entry : unknownFields.asMap().entrySet()) {
final int number = entry.getKey();
final UnknownFieldSet.Field field = entry.getValue();
printUnknownField(number, WireFormat.WIRETYPE_VARINT, field.getVarintList(), generator);
printUnknownField(number, WireFormat.WIRETYPE_FIXED32, field.getFixed32List(), generator);
printUnknownField(number, WireFormat.WIRETYPE_FIXED64, field.getFixed64List(), generator);
printUnknownField(
number, WireFormat.WIRETYPE_VARINT, field.getVarintList(), generator, redact);
printUnknownField(
number, WireFormat.WIRETYPE_FIXED32, field.getFixed32List(), generator, redact);
printUnknownField(
number, WireFormat.WIRETYPE_FIXED64, field.getFixed64List(), generator, redact);
printUnknownField(
number,
WireFormat.WIRETYPE_LENGTH_DELIMITED,
field.getLengthDelimitedList(),
generator);
generator,
redact);
for (final UnknownFieldSet value : field.getGroupList()) {
generator.print(entry.getKey().toString());
generator.print(" {");
generator.eol();
generator.indent();
printUnknownFields(value, generator);
printUnknownFields(value, generator, redact);
generator.outdent();
generator.print("}");
generator.eol();
@ -606,12 +742,16 @@ public final class TextFormat {
}
private static void printUnknownField(
final int number, final int wireType, final List<?> values, final TextGenerator generator)
final int number,
final int wireType,
final List<?> values,
final TextGenerator generator,
boolean redact)
throws IOException {
for (final Object value : values) {
generator.print(String.valueOf(number));
generator.print(": ");
printUnknownFieldValue(wireType, value, generator);
printUnknownFieldValue(wireType, value, generator, redact);
generator.eol();
}
}
@ -637,12 +777,8 @@ public final class TextFormat {
}
}
private static TextGenerator multiLineOutput(Appendable output) {
return new TextGenerator(output, false);
}
private static TextGenerator singleLineOutput(Appendable output) {
return new TextGenerator(output, true);
private static TextGenerator setSingleLineOutput(Appendable output, boolean singleLine) {
return new TextGenerator(output, singleLine);
}
/** An inner class for writing text to the output stream. */

@ -83,8 +83,17 @@ public final class UnknownFieldSet implements MessageLite {
return fields.hashCode();
}
/** Whether the field set has no fields. */
public boolean isEmpty() {
return fields.isEmpty();
}
/** Get a map of fields in the set by number. */
public Map<Integer, Field> asMap() {
// Avoid an allocation for the common case of an empty map.
if (fields.isEmpty()) {
return Collections.emptyMap();
}
return (Map<Integer, Field>) fields.clone();
}
@ -102,6 +111,10 @@ public final class UnknownFieldSet implements MessageLite {
/** Serializes the set and writes it to {@code output}. */
@Override
public void writeTo(CodedOutputStream output) throws IOException {
if (fields.isEmpty()) {
// Avoid allocating an iterator.
return;
}
for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
Field field = entry.getValue();
field.writeTo(entry.getKey(), output);
@ -174,16 +187,22 @@ public final class UnknownFieldSet implements MessageLite {
@Override
public int getSerializedSize() {
int result = 0;
if (!fields.isEmpty()) {
for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
result += entry.getValue().getSerializedSize(entry.getKey());
}
if (fields.isEmpty()) {
// Avoid allocating an iterator.
return result;
}
for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
result += entry.getValue().getSerializedSize(entry.getKey());
}
return result;
}
/** Serializes the set and writes it to {@code output} using {@code MessageSet} wire format. */
public void writeAsMessageSetTo(CodedOutputStream output) throws IOException {
if (fields.isEmpty()) {
// Avoid allocating an iterator.
return;
}
for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
entry.getValue().writeAsMessageSetExtensionTo(entry.getKey(), output);
}
@ -191,6 +210,10 @@ public final class UnknownFieldSet implements MessageLite {
/** Serializes the set and writes it to {@code writer}. */
void writeTo(Writer writer) throws IOException {
if (fields.isEmpty()) {
// Avoid allocating an iterator.
return;
}
if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) {
// Write fields in descending order.
for (Map.Entry<Integer, Field> entry : fields.descendingMap().entrySet()) {
@ -206,6 +229,10 @@ public final class UnknownFieldSet implements MessageLite {
/** Serializes the set and writes it to {@code writer} using {@code MessageSet} wire format. */
void writeAsMessageSetTo(Writer writer) throws IOException {
if (fields.isEmpty()) {
// Avoid allocating an iterator.
return;
}
if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) {
// Write fields in descending order.
for (Map.Entry<Integer, Field> entry : fields.descendingMap().entrySet()) {
@ -222,6 +249,10 @@ public final class UnknownFieldSet implements MessageLite {
/** Get the number of bytes required to encode this set using {@code MessageSet} wire format. */
public int getSerializedSizeAsMessageSet() {
int result = 0;
if (fields.isEmpty()) {
// Avoid allocating an iterator.
return result;
}
for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
result += entry.getValue().getSerializedSizeAsMessageSetExtension(entry.getKey());
}
@ -452,6 +483,11 @@ public final class UnknownFieldSet implements MessageLite {
* changes may or may not be reflected in this map.
*/
public Map<Integer, Field> asMap() {
// Avoid an allocation for the common case of an empty map.
if (fieldBuilders.isEmpty()) {
return Collections.emptyMap();
}
TreeMap<Integer, Field> fields = new TreeMap<>();
for (Map.Entry<Integer, Field.Builder> entry : fieldBuilders.entrySet()) {
fields.put(entry.getKey(), entry.getValue().build());

@ -0,0 +1,210 @@
package com.google.protobuf;
import static com.google.common.truth.Truth.assertThat;
import static protobuf_unittest.UnittestProto.redactedExtension;
import com.google.protobuf.Descriptors.FieldDescriptor;
import protobuf_unittest.UnittestProto.RedactedFields;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestNestedMessageRedaction;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public final class DebugFormatTest {
private static final String REDACTED_REGEX = "\\[REDACTED\\]";
private static final String UNSTABLE_PREFIX_SINGLE_LINE = getUnstablePrefix(true);
private static final String UNSTABLE_PREFIX_MULTILINE = getUnstablePrefix(false);
private static String getUnstablePrefix(boolean singleLine) {
return "";
}
@Test
public void multilineMessageFormat_returnsMultiline() {
RedactedFields message = RedactedFields.newBuilder().setOptionalUnredactedString("foo").build();
String result = DebugFormat.multiline().toString(message);
assertThat(result)
.matches(
String.format("%soptional_unredacted_string: \"foo\"\n", UNSTABLE_PREFIX_MULTILINE));
}
@Test
public void singleLineMessageFormat_returnsSingleLine() {
RedactedFields message = RedactedFields.newBuilder().setOptionalUnredactedString("foo").build();
String result = DebugFormat.singleLine().toString(message);
assertThat(result)
.matches(
String.format("%soptional_unredacted_string: \"foo\"", UNSTABLE_PREFIX_SINGLE_LINE));
}
@Test
public void messageFormat_debugRedactFieldIsRedacted() {
RedactedFields message = RedactedFields.newBuilder().setOptionalRedactedString("foo").build();
String result = DebugFormat.multiline().toString(message);
assertThat(result)
.matches(
String.format(
"%soptional_redacted_string: %s\n", UNSTABLE_PREFIX_MULTILINE, REDACTED_REGEX));
}
@Test
public void messageFormat_debugRedactMessageIsRedacted() {
RedactedFields message =
RedactedFields.newBuilder()
.setOptionalRedactedMessage(
TestNestedMessageRedaction.newBuilder().setOptionalUnredactedNestedString("foo"))
.build();
String result = DebugFormat.multiline().toString(message);
assertThat(result)
.matches(
String.format(
"%soptional_redacted_message \\{\n %s\n\\}\n",
UNSTABLE_PREFIX_MULTILINE, REDACTED_REGEX));
}
@Test
public void messageFormat_debugRedactMapIsRedacted() {
RedactedFields message = RedactedFields.newBuilder().putMapRedactedString("foo", "bar").build();
String result = DebugFormat.multiline().toString(message);
assertThat(result)
.matches(
String.format(
"%smap_redacted_string \\{\\n %s\n\\}\n",
UNSTABLE_PREFIX_MULTILINE, REDACTED_REGEX));
}
@Test
public void messageFormat_debugRedactExtensionIsRedacted() {
RedactedFields message =
RedactedFields.newBuilder().setExtension(redactedExtension, "foo").build();
String result = DebugFormat.multiline().toString(message);
assertThat(result)
.matches(
String.format(
"%s\\[protobuf_unittest\\.redacted_extension\\]: %s\n",
UNSTABLE_PREFIX_MULTILINE, REDACTED_REGEX));
}
@Test
public void messageFormat_redactFalseIsNotRedacted() {
RedactedFields message =
RedactedFields.newBuilder().setOptionalRedactedFalseString("foo").build();
String result = DebugFormat.multiline().toString(message);
assertThat(result)
.matches(
String.format(
"%soptional_redacted_false_string: \"foo\"\n", UNSTABLE_PREFIX_MULTILINE));
}
@Test
public void messageFormat_nonSensitiveFieldIsNotRedacted() {
RedactedFields message = RedactedFields.newBuilder().setOptionalUnredactedString("foo").build();
String result = DebugFormat.multiline().toString(message);
assertThat(result)
.matches(
String.format("%soptional_unredacted_string: \"foo\"\n", UNSTABLE_PREFIX_MULTILINE));
}
@Test
public void descriptorDebugFormat_returnsExpectedFormat() {
FieldDescriptor field =
RedactedFields.getDescriptor().findFieldByName("optional_redacted_string");
String result = DebugFormat.multiline().toString(field, "foo");
assertThat(result)
.matches(
String.format(
"%soptional_redacted_string: %s\n", UNSTABLE_PREFIX_MULTILINE, REDACTED_REGEX));
}
@Test
public void unstableFormat_isStablePerProcess() {
RedactedFields message1 =
RedactedFields.newBuilder().setOptionalUnredactedString("foo").build();
RedactedFields message2 =
RedactedFields.newBuilder().setOptionalUnredactedString("foo").build();
for (int i = 0; i < 5; i++) {
String result1 = DebugFormat.multiline().toString(message1);
String result2 = DebugFormat.multiline().toString(message2);
assertThat(result1).isEqualTo(result2);
}
}
@Test
public void lazyDebugFormatMessage_supportsImplicitFormatting() {
RedactedFields message = RedactedFields.newBuilder().setOptionalUnredactedString("foo").build();
Object lazyDebug = DebugFormat.singleLine().lazyToString(message);
assertThat(String.format("%s", lazyDebug))
.matches(
String.format("%soptional_unredacted_string: \"foo\"", UNSTABLE_PREFIX_SINGLE_LINE));
}
private UnknownFieldSet makeUnknownFieldSet() {
return UnknownFieldSet.newBuilder()
.addField(
5,
UnknownFieldSet.Field.newBuilder()
.addVarint(1)
.addFixed32(2)
.addFixed64(3)
.addLengthDelimited(ByteString.copyFromUtf8("4"))
.addLengthDelimited(
UnknownFieldSet.newBuilder()
.addField(12, UnknownFieldSet.Field.newBuilder().addVarint(6).build())
.build()
.toByteString())
.addGroup(
UnknownFieldSet.newBuilder()
.addField(10, UnknownFieldSet.Field.newBuilder().addVarint(5).build())
.build())
.build())
.addField(
8, UnknownFieldSet.Field.newBuilder().addVarint(1).addVarint(2).addVarint(3).build())
.addField(
15,
UnknownFieldSet.Field.newBuilder()
.addVarint(0xABCDEF1234567890L)
.addFixed32(0xABCD1234)
.addFixed64(0xABCDEF1234567890L)
.build())
.build();
}
@Test
public void unknownFieldsDebugFormat_returnsExpectedFormat() {
TestEmptyMessage unknownFields =
TestEmptyMessage.newBuilder().setUnknownFields(makeUnknownFieldSet()).build();
assertThat(DebugFormat.multiline().toString(unknownFields))
.matches(
String.format("%s5: UNKNOWN_VARINT %s\n", UNSTABLE_PREFIX_MULTILINE, REDACTED_REGEX)
+ String.format("5: UNKNOWN_FIXED32 %s\n", REDACTED_REGEX)
+ String.format("5: UNKNOWN_FIXED64 %s\n", REDACTED_REGEX)
+ String.format("5: UNKNOWN_STRING %s\n", REDACTED_REGEX)
+ String.format("5: \\{\n 12: UNKNOWN_VARINT %s\n\\}\n", REDACTED_REGEX)
+ String.format("5 \\{\n 10: UNKNOWN_VARINT %s\n\\}\n", REDACTED_REGEX)
+ String.format("8: UNKNOWN_VARINT %s\n", REDACTED_REGEX)
+ String.format("8: UNKNOWN_VARINT %s\n", REDACTED_REGEX)
+ String.format("8: UNKNOWN_VARINT %s\n", REDACTED_REGEX)
+ String.format("15: UNKNOWN_VARINT %s\n", REDACTED_REGEX)
+ String.format("15: UNKNOWN_FIXED32 %s\n", REDACTED_REGEX)
+ String.format("15: UNKNOWN_FIXED64 %s\n", REDACTED_REGEX));
}
}

@ -1158,7 +1158,7 @@ public class DescriptorsTest {
.setOptions(FileOptions.newBuilder().setJavaStringCheckUtf8(true))
.build(),
new FileDescriptor[0]);
assertThat(file.features.getExtension(JavaFeaturesProto.java).getUtf8Validation())
assertThat(file.features.getExtension(JavaFeaturesProto.java_).getUtf8Validation())
.isEqualTo(JavaFeaturesProto.JavaFeatures.Utf8Validation.VERIFY);
}
@ -1178,8 +1178,8 @@ public class DescriptorsTest {
assertThat(features.getJsonFormat())
.isEqualTo(DescriptorProtos.FeatureSet.JsonFormat.LEGACY_BEST_EFFORT);
assertThat(features.getExtension(JavaFeaturesProto.java).getLegacyClosedEnum()).isTrue();
assertThat(features.getExtension(JavaFeaturesProto.java).getUtf8Validation())
assertThat(features.getExtension(JavaFeaturesProto.java_).getLegacyClosedEnum()).isTrue();
assertThat(features.getExtension(JavaFeaturesProto.java_).getUtf8Validation())
.isEqualTo(JavaFeaturesProto.JavaFeatures.Utf8Validation.DEFAULT);
}
@ -1198,8 +1198,8 @@ public class DescriptorsTest {
assertThat(features.getMessageEncoding())
.isEqualTo(DescriptorProtos.FeatureSet.MessageEncoding.LENGTH_PREFIXED);
assertThat(features.getExtension(JavaFeaturesProto.java).getLegacyClosedEnum()).isFalse();
assertThat(features.getExtension(JavaFeaturesProto.java).getUtf8Validation())
assertThat(features.getExtension(JavaFeaturesProto.java_).getLegacyClosedEnum()).isFalse();
assertThat(features.getExtension(JavaFeaturesProto.java_).getUtf8Validation())
.isEqualTo(JavaFeaturesProto.JavaFeatures.Utf8Validation.DEFAULT);
}

@ -12,7 +12,10 @@ edition = "2023";
package proto2_test_check_utf8;
option features.utf8_validation = VERIFY;
import "google/protobuf/java_features.proto";
option features.utf8_validation = NONE;
option features.(pb.java).utf8_validation = VERIFY;
option java_outer_classname = "TestCheckUtf8";
message StringWrapper {

@ -225,7 +225,7 @@ class Proto2Test {
TestAllTypesKt.repeatedGroup { a = 1 },
TestAllTypesKt.repeatedGroup { a = 2 },
TestAllTypesKt.repeatedGroup { a = 3 },
TestAllTypesKt.repeatedGroup { a = 4 }
TestAllTypesKt.repeatedGroup { a = 4 },
)
)
repeatedGroup[0] = TestAllTypesKt.repeatedGroup { a = 5 }
@ -235,7 +235,7 @@ class Proto2Test {
TestAllTypesKt.repeatedGroup { a = 5 },
TestAllTypesKt.repeatedGroup { a = 2 },
TestAllTypesKt.repeatedGroup { a = 3 },
TestAllTypesKt.repeatedGroup { a = 4 }
TestAllTypesKt.repeatedGroup { a = 4 },
)
)
@ -249,7 +249,7 @@ class Proto2Test {
nestedMessage { bb = 1 },
nestedMessage { bb = 2 },
nestedMessage { bb = 3 },
nestedMessage { bb = 4 }
nestedMessage { bb = 4 },
)
)
repeatedNestedMessage[0] = nestedMessage { bb = 5 }
@ -259,7 +259,7 @@ class Proto2Test {
nestedMessage { bb = 5 },
nestedMessage { bb = 2 },
nestedMessage { bb = 3 },
nestedMessage { bb = 4 }
nestedMessage { bb = 4 },
)
)
@ -548,7 +548,7 @@ class Proto2Test {
repeatedGroupExtension { a = 1 },
repeatedGroupExtension { a = 2 },
repeatedGroupExtension { a = 3 },
repeatedGroupExtension { a = 4 }
repeatedGroupExtension { a = 4 },
)
)
this[UnittestProto.repeatedGroupExtension][0] = repeatedGroupExtension { a = 5 }
@ -558,7 +558,7 @@ class Proto2Test {
repeatedGroupExtension { a = 5 },
repeatedGroupExtension { a = 2 },
repeatedGroupExtension { a = 3 },
repeatedGroupExtension { a = 4 }
repeatedGroupExtension { a = 4 },
)
)
@ -575,7 +575,7 @@ class Proto2Test {
nestedMessage { bb = 1 },
nestedMessage { bb = 2 },
nestedMessage { bb = 3 },
nestedMessage { bb = 4 }
nestedMessage { bb = 4 },
)
)
this[UnittestProto.repeatedNestedMessageExtension][0] = nestedMessage { bb = 5 }
@ -585,7 +585,7 @@ class Proto2Test {
nestedMessage { bb = 5 },
nestedMessage { bb = 2 },
nestedMessage { bb = 3 },
nestedMessage { bb = 4 }
nestedMessage { bb = 4 },
)
)
@ -757,7 +757,7 @@ class Proto2Test {
1 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO,
2 to Proto2MapEnum.PROTO2_MAP_ENUM_BAR,
3 to Proto2MapEnum.PROTO2_MAP_ENUM_BAZ,
4 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO
4 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO,
)
)
}
@ -844,6 +844,11 @@ class Proto2Test {
cachedSize_ = "foo"
serializedSize_ = true
by = "foo"
dEPRECATEDFoo = "foo"
DEPRECATEDBar = "foo"
iD = "foo"
aBNotification = "foo"
notDEPRECATEDFoo = "foo"
}
)
.isEqualTo(
@ -869,6 +874,11 @@ class Proto2Test {
.setCachedSize_("foo")
.setSerializedSize_(true)
.setBy("foo")
.setDEPRECATEDFoo("foo")
.setDEPRECATEDBar("foo")
.setID("foo")
.setABNotification("foo")
.setNotDEPRECATEDFoo("foo")
.build()
)

@ -81,7 +81,7 @@ class Proto3Test {
nestedMessage { bb = 1 },
nestedMessage { bb = 2 },
nestedMessage { bb = 3 },
nestedMessage { bb = 4 }
nestedMessage { bb = 4 },
)
)
repeatedNestedMessage[0] = nestedMessage { bb = 5 }
@ -91,7 +91,7 @@ class Proto3Test {
nestedMessage { bb = 5 },
nestedMessage { bb = 2 },
nestedMessage { bb = 3 },
nestedMessage { bb = 4 }
nestedMessage { bb = 4 },
)
)
@ -200,6 +200,11 @@ class Proto3Test {
pairs["foo"] = 1
LeadingUnderscore = "foo"
option = 1
dEPRECATEDFoo = "foo"
iD = "foo"
aBNotification = "foo"
DEPRECATEDBar = "foo"
notDEPRECATEDFoo = "foo"
}
)
.isEqualTo(
@ -237,6 +242,11 @@ class Proto3Test {
.putPairs("foo", 1)
.setLeadingUnderscore("foo")
.setOption(1)
.setDEPRECATEDFoo("foo")
.setID("foo")
.setABNotification("foo")
.setDEPRECATEDBar("foo")
.setNotDEPRECATEDFoo("foo")
.build()
)

@ -43,6 +43,15 @@ message EvilNamesProto2 {
optional string cached_size = 23;
optional bool serialized_size = 24;
optional string by = 25;
optional string DEPRECATED_foo = 26;
optional group DEPRECATED_NavigationImageRequested = 27 {
optional int32 DEPRECATED_FooBar = 28;
}
optional string __DEPRECATED_Bar = 29;
optional string ID = 30;
optional string a_b_notification = 31;
optional string not_DEPRECATED_foo = 32;
}
message List {}

@ -56,6 +56,12 @@ message EvilNamesProto3 {
oneof _leading_underscore_oneof {
int32 option = 34;
}
optional string DEPRECATED_foo = 35;
optional string ID = 36;
optional string a_b_notification = 37;
optional string __DEPRECATED_Bar = 38;
optional string not_DEPRECATED_foo = 39;
}
message HardKeywordsAllTypesProto3 {

@ -139,6 +139,8 @@
<include>LazyStringArrayList.java</include>
<include>LazyStringList.java</include>
<include>ListFieldSchema.java</include>
<include>ListFieldSchemaLite.java</include>
<include>ListFieldSchemas.java</include>
<include>LongArrayList.java</include>
<include>ManifestSchemaFactory.java</include>
<include>MapEntryLite.java</include>

@ -2423,6 +2423,12 @@ public class LiteTest {
int unused = TestRecursiveOneof.getDefaultInstance().hashCode();
}
@Test
public void testParseFromEmptyBytes() throws Exception {
assertThat(TestAllTypesLite.parseFrom(new byte[] {}))
.isSameInstanceAs(TestAllTypesLite.getDefaultInstance());
}
@Test
public void testParseFromByteBuffer() throws Exception {
TestAllTypesLite message =
@ -2718,7 +2724,7 @@ public class LiteTest {
@Test
public void testNullExtensionRegistry() throws Exception {
try {
TestAllTypesLite.parseFrom(new byte[] {}, null);
TestAllTypesLite.parseFrom(TestUtilLite.getAllLiteSetBuilder().build().toByteArray(), null);
assertWithMessage("expected exception").fail();
} catch (NullPointerException expected) {
}

@ -1109,11 +1109,11 @@ message TestNestedGroupExtensionOuter {
repeated group Layer2RepeatedGroup = 2 {
extensions 3
// NOTE: extension metadata is not supported due to targets such as
// `//third_party/protobuf_legacy_opensource/src:shell_scripts_test`,
// `//google/protobuf_legacy_opensource/src:shell_scripts_test`,
// eee https://screenshot.googleplex.com/Axz2QD8nxjdpyFF
//[metadata = {
// NOTE: can't write type there due to some clever build gen code at
// http://google3/net/proto2/internal/BUILD;l=1247;rcl=411090862
// http://google3/google/protobuf/BUILD;l=1247;rcl=411090862
// type: "objc.protobuf.tests.TestNestedGroupExtensionInnerExtension",
// name: "inner",
// }]

@ -64,6 +64,7 @@ genrule(
conformance_test(
name = "conformance_test",
failure_list = "//conformance:failure_list_php.txt",
maximum_edition = "2023",
target_compatible_with = select({
"@platforms//os:osx": ["@platforms//:incompatible"],
"//conditions:default": [],
@ -75,6 +76,7 @@ conformance_test(
conformance_test(
name = "conformance_test_c",
failure_list = "//conformance:failure_list_php_c.txt",
maximum_edition = "2023",
target_compatible_with = select({
"@platforms//os:osx": [],
"//conditions:default": ["@platforms//:incompatible"],

@ -404,7 +404,8 @@ void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt,
* google/protobuf/descriptor.proto
*
* Do not edit -- your changes will be discarded when the file is
* regenerated. */
* regenerated.
* NO CHECKED-IN PROTOBUF GENCODE */
#include <stddef.h>
@ -1762,7 +1763,8 @@ const upb_MiniTableFile google_protobuf_descriptor_proto_upb_file_layout = {
* google/protobuf/descriptor.proto
*
* Do not edit -- your changes will be discarded when the file is
* regenerated. */
* regenerated.
* NO CHECKED-IN PROTOBUF GENCODE */
static const char descriptor[12155] = {'\n', ' ', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'e', 's', 'c', 'r', 'i', 'p',
@ -3119,6 +3121,7 @@ static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) {
/* Composite types (array/message/map) ****************************************/
static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array;
jsondec_arrstart(d);
@ -3132,6 +3135,7 @@ static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) {
}
static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map;
const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f);
const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1);
@ -3153,6 +3157,7 @@ static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) {
static void jsondec_tomsg(jsondec* d, upb_Message* msg,
const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) {
jsondec_object(d, msg, m);
} else {
@ -3173,6 +3178,7 @@ static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) {
static void jsondec_field(jsondec* d, upb_Message* msg,
const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_StringView name;
const upb_FieldDef* f;
const upb_FieldDef* preserved;
@ -3238,6 +3244,7 @@ static void jsondec_field(jsondec* d, upb_Message* msg,
static void jsondec_object(jsondec* d, upb_Message* msg,
const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
jsondec_objstart(d);
while (jsondec_objnext(d)) {
jsondec_field(d, msg, m);
@ -3338,6 +3345,7 @@ static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) {
static void jsondec_timestamp(jsondec* d, upb_Message* msg,
const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_MessageValue seconds;
upb_MessageValue nanos;
upb_StringView str = jsondec_string(d);
@ -3403,6 +3411,7 @@ malformed:
static void jsondec_duration(jsondec* d, upb_Message* msg,
const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_MessageValue seconds;
upb_MessageValue nanos;
upb_StringView str = jsondec_string(d);
@ -3435,6 +3444,7 @@ static void jsondec_duration(jsondec* d, upb_Message* msg,
static void jsondec_listvalue(jsondec* d, upb_Message* msg,
const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1);
const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f);
const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m);
@ -3453,6 +3463,7 @@ static void jsondec_listvalue(jsondec* d, upb_Message* msg,
static void jsondec_struct(jsondec* d, upb_Message* msg,
const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1);
const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f);
const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
@ -3475,6 +3486,7 @@ static void jsondec_struct(jsondec* d, upb_Message* msg,
static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg,
const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_MessageValue val;
const upb_FieldDef* f;
upb_Message* submsg;
@ -3563,6 +3575,7 @@ static upb_StringView jsondec_mask(jsondec* d, const char* buf,
static void jsondec_fieldmask(jsondec* d, upb_Message* msg,
const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
/* repeated string paths = 1; */
const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1);
upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array;
@ -3586,6 +3599,7 @@ static void jsondec_fieldmask(jsondec* d, upb_Message* msg,
static void jsondec_anyfield(jsondec* d, upb_Message* msg,
const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) {
/* For regular types: {"@type": "[user type]", "f1": <V1>, "f2": <V2>}
* where f1, f2, etc. are the normal fields of this type. */
@ -3604,6 +3618,7 @@ static void jsondec_anyfield(jsondec* d, upb_Message* msg,
static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg,
const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1);
const upb_MessageDef* type_m;
upb_StringView type_url = jsondec_string(d);
@ -3633,6 +3648,7 @@ static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg,
}
static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
/* string type_url = 1;
* bytes value = 2; */
const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2);
@ -3701,6 +3717,7 @@ static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) {
static void jsondec_wrapper(jsondec* d, upb_Message* msg,
const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1);
upb_JsonMessageValue val = jsondec_value(d, value_f);
UPB_ASSUME(val.ignore == false); // Wrapper cannot be an enum.
@ -3709,6 +3726,7 @@ static void jsondec_wrapper(jsondec* d, upb_Message* msg,
static void jsondec_wellknown(jsondec* d, upb_Message* msg,
const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
switch (upb_MessageDef_WellKnownType(m)) {
case kUpb_WellKnown_Any:
jsondec_any(d, msg, m);
@ -3749,6 +3767,7 @@ static void jsondec_wellknown(jsondec* d, upb_Message* msg,
static bool upb_JsonDecoder_Decode(jsondec* const d, upb_Message* const msg,
const upb_MessageDef* const m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
if (UPB_SETJMP(d->err)) return false;
jsondec_tomsg(d, msg, m);
@ -5137,10 +5156,8 @@ bool upb_Message_SetMapEntry(upb_Map* map, const upb_MiniTable* m,
const upb_MiniTableField* f,
upb_Message* map_entry_message, upb_Arena* arena) {
UPB_ASSERT(!upb_Message_IsFrozen(map_entry_message));
// TODO: use a variant of upb_MiniTable_GetSubMessageTable() here.
const upb_MiniTable* map_entry_mini_table = upb_MiniTableSub_Message(
m->UPB_PRIVATE(subs)[f->UPB_PRIVATE(submsg_index)]);
const upb_MiniTable* map_entry_mini_table =
upb_MiniTable_MapEntrySubMessage(m, f);
UPB_ASSERT(map_entry_mini_table);
const upb_MiniTableField* map_entry_key_field =
upb_MiniTable_MapKey(map_entry_mini_table);
@ -6043,9 +6060,9 @@ static upb_Map* upb_Message_Map_DeepClone(const upb_Map* map,
const upb_MiniTableField* f,
upb_Message* clone,
upb_Arena* arena) {
// TODO: use a variant of upb_MiniTable_GetSubMessageTable() here.
const upb_MiniTable* map_entry_table = upb_MiniTableSub_Message(
mini_table->UPB_PRIVATE(subs)[f->UPB_PRIVATE(submsg_index)]);
UPB_ASSERT(!upb_Message_IsFrozen(clone));
const upb_MiniTable* map_entry_table =
upb_MiniTable_MapEntrySubMessage(mini_table, f);
UPB_ASSERT(map_entry_table);
const upb_MiniTableField* key_field = upb_MiniTable_MapKey(map_entry_table);
@ -6087,6 +6104,7 @@ static bool upb_Message_Array_DeepClone(const upb_Array* array,
const upb_MiniTable* mini_table,
const upb_MiniTableField* field,
upb_Message* clone, upb_Arena* arena) {
UPB_ASSERT(!upb_Message_IsFrozen(clone));
UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(field);
upb_Array* cloned_array = upb_Array_DeepClone(
array, upb_MiniTableField_CType(field),
@ -6112,6 +6130,7 @@ static bool upb_Clone_ExtensionValue(
upb_Message* _upb_Message_Copy(upb_Message* dst, const upb_Message* src,
const upb_MiniTable* mini_table,
upb_Arena* arena) {
UPB_ASSERT(!upb_Message_IsFrozen(dst));
upb_StringView empty_string = upb_StringView_FromDataAndSize(NULL, 0);
// Only copy message area skipping upb_Message_Internal.
memcpy(dst + 1, src + 1, mini_table->UPB_PRIVATE(size) - sizeof(upb_Message));
@ -6138,10 +6157,10 @@ upb_Message* _upb_Message_Copy(upb_Message* dst, const upb_Message* src,
if (dst_sub_message == NULL) {
return NULL;
}
_upb_Message_SetTaggedMessagePtr(
dst, mini_table, field,
UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(dst_sub_message,
is_empty));
UPB_PRIVATE(_upb_Message_SetTaggedMessagePtr)
(dst, field,
UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(dst_sub_message,
is_empty));
}
} break;
case kUpb_CType_String:
@ -6218,6 +6237,7 @@ upb_Message* _upb_Message_Copy(upb_Message* dst, const upb_Message* src,
bool upb_Message_DeepCopy(upb_Message* dst, const upb_Message* src,
const upb_MiniTable* mini_table, upb_Arena* arena) {
UPB_ASSERT(!upb_Message_IsFrozen(dst));
upb_Message_Clear(dst, mini_table);
return _upb_Message_Copy(dst, src, mini_table, arena) != NULL;
}
@ -6234,6 +6254,7 @@ upb_Message* upb_Message_DeepClone(const upb_Message* msg,
// Performs a shallow copy. TODO: Extend to handle unknown fields.
void upb_Message_ShallowCopy(upb_Message* dst, const upb_Message* src,
const upb_MiniTable* m) {
UPB_ASSERT(!upb_Message_IsFrozen(dst));
memcpy(dst, src, m->UPB_PRIVATE(size));
}
@ -7284,12 +7305,12 @@ bool upb_MiniTable_SetSubMessage(upb_MiniTable* table,
return false;
}
upb_MiniTableSub* table_sub =
(void*)&table->UPB_PRIVATE(subs)[field->UPB_PRIVATE(submsg_index)];
int idx = field->UPB_PRIVATE(submsg_index);
upb_MiniTableSub* table_subs = (void*)table->UPB_PRIVATE(subs);
// TODO: Add this assert back once YouTube is updated to not call
// this function repeatedly.
// UPB_ASSERT(UPB_PRIVATE(_upb_MiniTable_IsEmpty)(table_sub->submsg));
*table_sub = upb_MiniTableSub_FromMessage(sub);
table_subs[idx] = upb_MiniTableSub_FromMessage(sub);
return true;
}
@ -9854,6 +9875,7 @@ UPB_FORCEINLINE
void* fastdecode_getfield(upb_Decoder* d, const char* ptr, upb_Message* msg,
uint64_t* data, uint64_t* hasbits,
fastdecode_arr* farr, int valbytes, upb_card card) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
switch (card) {
case CARD_s: {
uint8_t hasbit_index = *data >> 24;
@ -10229,6 +10251,7 @@ UPB_NOINLINE
static const char* fastdecode_verifyutf8(upb_Decoder* d, const char* ptr,
upb_Message* msg, intptr_t table,
uint64_t hasbits, uint64_t data) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_StringView* dst = (upb_StringView*)data;
if (!_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) {
_upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8);
@ -10274,6 +10297,7 @@ UPB_NOINLINE
static const char* fastdecode_longstring_noutf8(
struct upb_Decoder* d, const char* ptr, upb_Message* msg, intptr_t table,
uint64_t hasbits, uint64_t data) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_StringView* dst = (upb_StringView*)data;
FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, false);
}
@ -11974,6 +11998,7 @@ const upb_Extension* UPB_PRIVATE(_upb_Message_Getexts)(
upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtension)(
struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_Extension* ext = (upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e);
if (ext) return ext;
if (!UPB_PRIVATE(_upb_Message_Realloc)(msg, sizeof(upb_Extension), a))
@ -11999,6 +12024,7 @@ const double kUpb_NaN = NAN;
bool UPB_PRIVATE(_upb_Message_Realloc)(struct upb_Message* msg, size_t need,
upb_Arena* a) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
const size_t overhead = sizeof(upb_Message_Internal);
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
@ -12035,21 +12061,19 @@ bool UPB_PRIVATE(_upb_Message_Realloc)(struct upb_Message* msg, size_t need,
}
#if UPB_TRACING_ENABLED
static void (*_new_message_trace_handler)(const upb_MiniTable*,
const upb_Arena*);
static void (*_message_trace_handler)(const upb_MiniTable*, const upb_Arena*);
void UPB_PRIVATE(upb_Message_SetNewMessageTraceHandler)(
void (*new_message_trace_handler)(const upb_MiniTable*, const upb_Arena*)) {
_new_message_trace_handler = new_message_trace_handler;
void upb_Message_LogNewMessage(const upb_MiniTable* m, const upb_Arena* arena) {
if (_message_trace_handler) {
_message_trace_handler(m, arena);
}
}
void UPB_PRIVATE(upb_Message_LogNewMessage)(const upb_MiniTable* mini_table,
const upb_Arena* arena) {
if (_new_message_trace_handler) {
_new_message_trace_handler(mini_table, arena);
}
void upb_Message_SetNewMessageTraceHandler(void (*handler)(const upb_MiniTable*,
const upb_Arena*)) {
_message_trace_handler = handler;
}
#endif
#endif // UPB_TRACING_ENABLED
const char _kUpb_ToBase92[] = {
@ -13673,11 +13697,11 @@ upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) {
}
const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) {
return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL;
return upb_FieldDef_IsSubMessage(f) ? f->sub.msgdef : NULL;
}
const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) {
return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL;
return upb_FieldDef_IsEnum(f) ? f->sub.enumdef : NULL;
}
const upb_MiniTableField* upb_FieldDef_MiniTable(const upb_FieldDef* f) {
@ -13775,8 +13799,11 @@ bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; }
bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { return f->has_presence; }
bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) {
return upb_FieldDef_IsSubMessage(f) ||
upb_FieldDef_CType(f) == kUpb_CType_Enum;
return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsEnum(f);
}
bool upb_FieldDef_IsEnum(const upb_FieldDef* f) {
return upb_FieldDef_CType(f) == kUpb_CType_Enum;
}
bool upb_FieldDef_IsMap(const upb_FieldDef* f) {
@ -15401,6 +15428,7 @@ upb_MessageValue upb_Message_GetFieldByDef(const upb_Message* msg,
upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg,
const upb_FieldDef* f,
upb_Arena* a) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
UPB_ASSERT(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsRepeated(f));
if (upb_FieldDef_HasPresence(f) && !upb_Message_HasFieldByDef(msg, f)) {
// We need to skip the upb_Message_GetFieldByDef() call in this case.
@ -15439,6 +15467,7 @@ make:
bool upb_Message_SetFieldByDef(upb_Message* msg, const upb_FieldDef* f,
upb_MessageValue val, upb_Arena* a) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
const upb_MiniTableField* m_f = upb_FieldDef_MiniTable(f);
if (upb_MiniTableField_IsExtension(m_f)) {
@ -15451,6 +15480,7 @@ bool upb_Message_SetFieldByDef(upb_Message* msg, const upb_FieldDef* f,
}
void upb_Message_ClearFieldByDef(upb_Message* msg, const upb_FieldDef* f) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
const upb_MiniTableField* m_f = upb_FieldDef_MiniTable(f);
if (upb_MiniTableField_IsExtension(m_f)) {
@ -15461,6 +15491,7 @@ void upb_Message_ClearFieldByDef(upb_Message* msg, const upb_FieldDef* f) {
}
void upb_Message_ClearByDef(upb_Message* msg, const upb_MessageDef* m) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_Message_Clear(msg, upb_MessageDef_MiniTable(m));
}
@ -15522,6 +15553,7 @@ bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m,
bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m,
int depth) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
size_t iter = kUpb_Message_Begin;
const upb_FieldDef* f;
upb_MessageValue val;

File diff suppressed because it is too large Load Diff

@ -394,7 +394,8 @@ class Message
}
break;
case GPBType::STRING:
// TODO: Add utf-8 check.
// We don't check UTF-8 here; that will be validated by the
// setter later.
if (!GPBWire::readString($input, $value)) {
throw new GPBDecodeException(
"Unexpected EOF inside string field.");

@ -683,6 +683,21 @@ class EncodeDecodeTest extends TestBase
$m->mergeFromString(hex2bin('7201'));
}
public function testDecodeInvalidStringDataBadUtf8()
{
$this->expectException(Exception::class);
$m = new TestMessage();
$m->mergeFromString(hex2bin('720180'));
}
public function testDecodeValidStringData()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('720161'));
$this->assertSame('a', $m->getOptionalString());
}
public function testDecodeInvalidBytesLengthMiss()
{
$this->expectException(Exception::class);

@ -80,6 +80,7 @@ def _proto_gen_impl(ctx):
srcs = ctx.files.srcs
langs = ctx.attr.langs or []
out_type = ctx.attr.out_type
enable_editions = ctx.attr.enable_editions
deps = depset(direct = ctx.files.srcs)
source_dir = _SourceDir(ctx)
gen_dir = _GenDir(ctx).rstrip("/")
@ -130,6 +131,8 @@ def _proto_gen_impl(ctx):
generated_files = []
for src in srcs:
args = []
if enable_editions:
args.append("--experimental_editions")
in_gen_dir = src.root.path == gen_dir
if in_gen_dir:
@ -231,6 +234,7 @@ Args:
srcs: Protocol Buffers definition files (.proto) to run the protocol compiler
against.
deps: a list of dependency labels; must be other proto libraries.
enable_editions: if true, sets the --experimental_editions flag.
includes: a list of include paths to .proto files.
protoc: the label of the protocol compiler to generate the sources.
plugin: the label of the protocol compiler plugin to be passed to the protocol
@ -247,6 +251,7 @@ _proto_gen = rule(
attrs = {
"srcs": attr.label_list(allow_files = True),
"deps": attr.label_list(providers = [ProtoGenInfo]),
"enable_editions": attr.bool(),
"includes": attr.string_list(),
"protoc": attr.label(
cfg = "exec",
@ -655,6 +660,7 @@ def _source_proto_library(
protoc = Label("//:protoc"),
testonly = None,
visibility = ["//visibility:public"],
enable_editions = False,
**kwargs):
"""Bazel rule to create generated protobuf code from proto source files for
languages not well supported by Bazel yet. This will output the generated
@ -699,6 +705,7 @@ def _source_proto_library(
srcs = proto_deps,
protoc = protoc,
includes = includes,
enable_editions = enable_editions,
)
full_deps.append(":%s_deps_genproto" % name)
@ -712,6 +719,7 @@ def _source_proto_library(
protoc = protoc,
testonly = testonly,
visibility = visibility,
enable_editions = enable_editions,
)
native.filegroup(

@ -2,6 +2,7 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("//python/dist:python_downloads.bzl", "python_nuget_package", "python_source_archive")
load("//python/dist:system_python.bzl", "system_python")
PROTOBUF_MAVEN_ARTIFACTS = [
"com.google.caliper:caliper:1.0-beta-3",
@ -43,6 +44,8 @@ def protobuf_deps():
_github_archive(
name = "com_google_absl",
repo = "https://github.com/abseil/abseil-cpp",
# TODO: use Layout::WithStaticSizes in SerialArenaChunk when we update
# abseil to new release.
commit = "4a2c63365eff8823a5221db86ef490e828306f9d", # Abseil LTS 20240116.0
sha256 = "f49929d22751bf70dd61922fb1fd05eb7aec5e7a7f870beece79a6e28f0a06c1",
)
@ -102,6 +105,12 @@ def protobuf_deps():
url = "https://github.com/bazelbuild/rules_python/releases/download/0.26.0/rules_python-0.26.0.tar.gz",
)
if not native.existing_rule("system_python"):
system_python(
name = "system_python",
minimum_python_version = "3.7",
)
if not native.existing_rule("rules_jvm_external"):
_github_archive(
name = "rules_jvm_external",

@ -340,29 +340,28 @@ ABSL_MUST_USE_RESULT bool HasExtension(
return HasExtension(protos::Ptr(message), id);
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>, typename = EnableIfMutableProto<T>>
template <typename T, typename Extension, typename = EnableIfProtosClass<T>,
typename = EnableIfMutableProto<T>>
void ClearExtension(
Ptr<T> message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) {
const ::protos::internal::ExtensionIdentifier<T, Extension>& id) {
static_assert(!std::is_const_v<T>, "");
upb_Message_ClearExtension(internal::GetInternalMsg(message),
id.mini_table_ext());
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>>
template <typename T, typename Extension, typename = EnableIfProtosClass<T>>
void ClearExtension(
T* message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) {
const ::protos::internal::ExtensionIdentifier<T, Extension>& id) {
ClearExtension(::protos::Ptr(message), id);
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>, typename = EnableIfMutableProto<T>>
template <typename T, typename Extension, typename = EnableIfProtosClass<T>,
typename = EnableIfMutableProto<T>>
absl::Status SetExtension(
Ptr<T> message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id,
const ::protos::internal::ExtensionIdentifier<T, Extension>& id,
const Extension& value) {
static_assert(!std::is_const_v<T>);
auto* message_arena = static_cast<upb_Arena*>(message->GetInternalArena());
@ -371,11 +370,24 @@ absl::Status SetExtension(
internal::GetInternalMsg(&value));
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>, typename = EnableIfMutableProto<T>>
template <typename T, typename Extension, typename = EnableIfProtosClass<T>,
typename = EnableIfMutableProto<T>>
absl::Status SetExtension(
Ptr<T> message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id,
const ::protos::internal::ExtensionIdentifier<T, Extension>& id,
Ptr<Extension> value) {
static_assert(!std::is_const_v<T>);
auto* message_arena = static_cast<upb_Arena*>(message->GetInternalArena());
return ::protos::internal::SetExtension(internal::GetInternalMsg(message),
message_arena, id.mini_table_ext(),
internal::GetInternalMsg(value));
}
template <typename T, typename Extension, typename = EnableIfProtosClass<T>,
typename = EnableIfMutableProto<T>>
absl::Status SetExtension(
Ptr<T> message,
const ::protos::internal::ExtensionIdentifier<T, Extension>& id,
Extension&& value) {
Extension ext = std::move(value);
static_assert(!std::is_const_v<T>);
@ -386,25 +398,28 @@ absl::Status SetExtension(
internal::GetInternalMsg(&ext), extension_arena);
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>>
template <typename T, typename Extension, typename = EnableIfProtosClass<T>>
absl::Status SetExtension(
T* message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id,
T* message, const ::protos::internal::ExtensionIdentifier<T, Extension>& id,
const Extension& value) {
return ::protos::SetExtension(::protos::Ptr(message), id, value);
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>>
template <typename T, typename Extension, typename = EnableIfProtosClass<T>>
absl::Status SetExtension(
T* message,
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id,
T* message, const ::protos::internal::ExtensionIdentifier<T, Extension>& id,
Extension&& value) {
return ::protos::SetExtension(::protos::Ptr(message), id,
std::forward<Extension>(value));
}
template <typename T, typename Extension, typename = EnableIfProtosClass<T>>
absl::Status SetExtension(
T* message, const ::protos::internal::ExtensionIdentifier<T, Extension>& id,
Ptr<Extension> value) {
return ::protos::SetExtension(::protos::Ptr(message), id, value);
}
template <typename T, typename Extendee, typename Extension,
typename = EnableIfProtosClass<T>>
absl::StatusOr<Ptr<const Extension>> GetExtension(

@ -7,11 +7,14 @@
#include "protos_generator/gen_messages.h"
#include <cstddef>
#include <string>
#include <vector>
#include "google/protobuf/descriptor.pb.h"
#include "absl/strings/ascii.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/descriptor.h"
#include "protos_generator/gen_accessors.h"
#include "protos_generator/gen_enums.h"
@ -120,6 +123,55 @@ void WriteModelAccessDeclaration(const protobuf::Descriptor* descriptor,
output("};\n");
}
std::string UnderscoresToCamelCase(absl::string_view input,
bool cap_next_letter) {
std::string result;
for (size_t i = 0; i < input.size(); i++) {
if (absl::ascii_islower(input[i])) {
if (cap_next_letter) {
result += absl::ascii_toupper(input[i]);
} else {
result += input[i];
}
cap_next_letter = false;
} else if (absl::ascii_isupper(input[i])) {
// Capital letters are left as-is.
result += input[i];
cap_next_letter = false;
} else if (absl::ascii_isdigit(input[i])) {
result += input[i];
cap_next_letter = true;
} else {
cap_next_letter = true;
}
}
return result;
}
std::string FieldConstantName(const protobuf::FieldDescriptor* field) {
std::string field_name = UnderscoresToCamelCase(field->name(), true);
std::string result = absl::StrCat("k", field_name, "FieldNumber");
if (!field->is_extension() &&
field->containing_type()->FindFieldByCamelcaseName(
field->camelcase_name()) != field) {
// This field's camelcase name is not unique, add field number to make it
// unique.
absl::StrAppend(&result, "_", field->number());
}
return result;
}
void WriteConstFieldNumbers(Output& output,
const protobuf::Descriptor* descriptor) {
for (auto field : FieldRange(descriptor)) {
output("static constexpr ::uint32_t $0 = $1;\n", FieldConstantName(field),
field->number());
}
output("\n\n");
}
void WriteModelPublicDeclaration(
const protobuf::Descriptor* descriptor,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
@ -178,6 +230,7 @@ void WriteModelPublicDeclaration(
)cc",
ClassName(descriptor));
output("\n");
WriteConstFieldNumbers(output, descriptor);
output(
R"cc(
private:

@ -5,10 +5,12 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include <cstdint>
#include <iterator>
#include <limits>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
@ -23,10 +25,13 @@
#include "protos_generator/tests/no_package.upb.proto.h"
#include "protos_generator/tests/test_model.upb.proto.h"
#include "upb/mem/arena.h"
#include "upb/mem/arena.hpp"
namespace {
using ::protos_generator::test::protos::ChildModel1;
using ::protos_generator::test::protos::container_ext;
using ::protos_generator::test::protos::ContainerExtension;
using ::protos_generator::test::protos::other_ext;
using ::protos_generator::test::protos::RED;
using ::protos_generator::test::protos::TestEnum;
@ -38,7 +43,6 @@ using ::protos_generator::test::protos::TestModel_Category_VIDEO;
using ::protos_generator::test::protos::theme;
using ::protos_generator::test::protos::ThemeExtension;
using ::testing::ElementsAre;
using ::testing::HasSubstr;
// C++17 port of C++20 `requires`
template <typename... T, typename F>
@ -441,7 +445,7 @@ TEST(CppGeneratedCode, RepeatedScalarIterator) {
EXPECT_EQ(sum, 5 + 16 + 27);
// Access by const reference.
sum = 0;
for (const int& i : *test_model.mutable_value_array()) {
for (const auto& i : *test_model.mutable_value_array()) {
sum += i;
}
EXPECT_EQ(sum, 5 + 16 + 27);
@ -550,7 +554,7 @@ TEST(CppGeneratedCode, RepeatedFieldProxyForMessages) {
}
i = 0;
for (auto child : *test_model.mutable_child_models()) {
for (const auto& child : *test_model.mutable_child_models()) {
if (i++ == 0) {
EXPECT_EQ(child.child_str1(), kTestStr1);
} else {
@ -724,6 +728,70 @@ TEST(CppGeneratedCode, SetExtension) {
EXPECT_EQ(::protos::internal::GetInternalMsg(*ext), prior_message);
}
TEST(CppGeneratedCode, SetExtensionWithPtr) {
::protos::Arena arena_model;
::protos::Ptr<TestModel> model =
::protos::CreateMessage<TestModel>(arena_model);
void* prior_message;
{
// Use a nested scope to make sure the arenas are fused correctly.
::protos::Arena arena;
::protos::Ptr<ThemeExtension> extension1 =
::protos::CreateMessage<ThemeExtension>(arena);
extension1->set_ext_name("Hello World");
prior_message = ::protos::internal::GetInternalMsg(extension1);
EXPECT_EQ(false, ::protos::HasExtension(model, theme));
auto res = ::protos::SetExtension(model, theme, extension1);
EXPECT_EQ(true, res.ok());
}
EXPECT_EQ(true, ::protos::HasExtension(model, theme));
auto ext = ::protos::GetExtension(model, theme);
EXPECT_TRUE(ext.ok());
EXPECT_NE(::protos::internal::GetInternalMsg(*ext), prior_message);
}
#ifndef _MSC_VER
TEST(CppGeneratedCode, SetExtensionShouldNotCompileForWrongType) {
::protos::Arena arena;
::protos::Ptr<TestModel> model = ::protos::CreateMessage<TestModel>(arena);
ThemeExtension extension1;
ContainerExtension extension2;
const auto canSetExtension = [&](auto l) {
return Requires<decltype(model)>(l);
};
EXPECT_TRUE(canSetExtension(
[](auto p) -> decltype(::protos::SetExtension(p, theme, extension1)) {}));
// Wrong extension value type should fail to compile.
EXPECT_TRUE(!canSetExtension(
[](auto p) -> decltype(::protos::SetExtension(p, theme, extension2)) {}));
// Wrong extension id with correct extension type should fail to compile.
EXPECT_TRUE(
!canSetExtension([](auto p) -> decltype(::protos::SetExtension(
p, container_ext, extension1)) {}));
}
#endif
TEST(CppGeneratedCode, SetExtensionWithPtrSameArena) {
::protos::Arena arena;
::protos::Ptr<TestModel> model = ::protos::CreateMessage<TestModel>(arena);
void* prior_message;
{
// Use a nested scope to make sure the arenas are fused correctly.
::protos::Ptr<ThemeExtension> extension1 =
::protos::CreateMessage<ThemeExtension>(arena);
extension1->set_ext_name("Hello World");
prior_message = ::protos::internal::GetInternalMsg(extension1);
EXPECT_EQ(false, ::protos::HasExtension(model, theme));
auto res = ::protos::SetExtension(model, theme, extension1);
EXPECT_EQ(true, res.ok());
}
EXPECT_EQ(true, ::protos::HasExtension(model, theme));
auto ext = ::protos::GetExtension(model, theme);
EXPECT_TRUE(ext.ok());
EXPECT_NE(::protos::internal::GetInternalMsg(*ext), prior_message);
}
TEST(CppGeneratedCode, SetExtensionFusingFailureShouldCopy) {
// Use an initial block to disallow fusing.
char initial_block[1000];
@ -1134,6 +1202,11 @@ TEST(CppGeneratedCode, HasExtensionAndRegistry) {
EXPECT_TRUE(::protos::HasExtension(&parsed_model, theme));
}
TEST(CppGeneratedCode, FieldNumberConstants) {
static_assert(TestModel::kChildMapFieldNumber == 225);
EXPECT_EQ(225, TestModel::kChildMapFieldNumber);
}
// TODO : Add BUILD rule to test failures below.
#ifdef TEST_CLEAR_MESSAGE_FAILURE
TEST(CppGeneratedCode, ClearConstMessageShouldFail) {

@ -14,6 +14,8 @@ import "protos_generator/tests/child_model.proto";
message TestModelContainer {
repeated TestModel models = 1;
optional ChildModel3 proto_3_child = 2;
extensions 10000 to max
[verification = UNVERIFIED];
}
message TestModel {
@ -138,6 +140,17 @@ extend TestModel {
optional ThemeExtension theme = 12001;
}
message ContainerExtension {
extend TestModelContainer {
optional ContainerExtension container_extension = 12004;
}
optional string ext_container_name = 1;
}
extend TestModelContainer {
optional ContainerExtension container_ext = 12005;
}
message OtherExtension {
optional string ext2_name = 1;
}

@ -416,6 +416,11 @@ def build_targets(name):
srcs = ["google/protobuf/internal/wire_format_test.py"],
)
internal_py_test(
name = "proto_test",
srcs = ["google/protobuf/internal/proto_test.py"],
)
native.cc_library(
name = "proto_api",
hdrs = ["google/protobuf/proto_api.h"],

@ -884,6 +884,10 @@ class DescriptorCopyToProtoTest(unittest.TestCase):
name: 'FOREIGN_BAX'
number: 32
>
value: <
name: 'FOREIGN_LARGE'
number: 123456
>
"""
self._InternalTestCopyToProto(

@ -12,6 +12,8 @@ on proto classes. For usage, see:
reflection_test.py
"""
import sys
__author__ = 'rabsatt@google.com (Kevin Rabsatt)'
@ -99,3 +101,12 @@ class EnumTypeWrapper(object):
pass # fall out to break exception chaining
raise AttributeError('Enum {} has no value defined for name {!r}'.format(
self._enum_type.name, name))
def __or__(self, other):
"""Returns the union type of self and other."""
if sys.version_info >= (3, 10):
return type(self) | other
else:
raise NotImplementedError(
'You may not use | on EnumTypes (or classes) below python 3.10'
)

@ -1439,7 +1439,7 @@ class JsonFormatTest(JsonFormatBase):
def testInvalidAny(self):
message = any_pb2.Any()
text = '{"@type": "type.googleapis.com/google.protobuf.Int32Value"}'
self.assertRaisesRegex(KeyError, 'value', json_format.Parse, text, message)
self.assertRaisesRegex(json_format.ParseError, 'KeyError: \'value\'', json_format.Parse, text, message)
text = '{"value": 1234}'
self.assertRaisesRegex(
json_format.ParseError,
@ -1662,6 +1662,12 @@ class JsonFormatTest(JsonFormatBase):
json_format.Parse(json_string, new_parsed_message)
self.assertEqual(new_message, new_parsed_message)
def testOtherParseErrors(self):
self.CheckError(
'9',
"Failed to parse JSON: TypeError: 'int' object is not iterable.",
)
if __name__ == '__main__':
unittest.main()

@ -22,6 +22,7 @@ import operator
import pickle
import pydoc
import sys
import types
import unittest
from unittest import mock
import warnings
@ -30,6 +31,7 @@ cmp = lambda x, y: (x > y) - (x < y)
from google.protobuf.internal import api_implementation # pylint: disable=g-import-not-at-top
from google.protobuf.internal import encoder
from google.protobuf.internal import enum_type_wrapper
from google.protobuf.internal import more_extensions_pb2
from google.protobuf.internal import more_messages_pb2
from google.protobuf.internal import packed_field_test_pb2
@ -1314,6 +1316,44 @@ class MessageTest(unittest.TestCase):
self.assertNotEqual(m, ComparesWithFoo())
self.assertNotEqual(ComparesWithFoo(), m)
def testTypeUnion(self, message_module):
# Below python 3.10 you cannot create union types with the | operator, so we
# skip testing for unions with old versions.
if sys.version_info < (3, 10):
return
enum_type = enum_type_wrapper.EnumTypeWrapper(
message_module.TestAllTypes.NestedEnum.DESCRIPTOR
)
union_type = enum_type | int
self.assertIsInstance(union_type, types.UnionType)
def get_union() -> union_type:
return enum_type
union = get_union()
self.assertIsInstance(union, enum_type_wrapper.EnumTypeWrapper)
self.assertEqual(
union.DESCRIPTOR, message_module.TestAllTypes.NestedEnum.DESCRIPTOR
)
def testIn(self, message_module):
m = message_module.TestAllTypes()
self.assertNotIn('optional_nested_message', m)
self.assertNotIn('oneof_bytes', m)
self.assertNotIn('oneof_string', m)
with self.assertRaises(ValueError) as e:
'repeated_int32' in m
with self.assertRaises(ValueError) as e:
'repeated_nested_message' in m
with self.assertRaises(ValueError) as e:
1 in m
with self.assertRaises(ValueError) as e:
'not_a_field' in m
test_util.SetAllFields(m)
self.assertIn('optional_nested_message', m)
self.assertIn('oneof_bytes', m)
self.assertNotIn('oneof_string', m)
# Class to test proto2-only features (required, extensions, etc.)
@testing_refleaks.TestCase
@ -1345,6 +1385,9 @@ class Proto2Test(unittest.TestCase):
self.assertTrue(message.HasField('optional_int32'))
self.assertTrue(message.HasField('optional_bool'))
self.assertTrue(message.HasField('optional_nested_message'))
self.assertIn('optional_int32', message)
self.assertIn('optional_bool', message)
self.assertIn('optional_nested_message', message)
# Set the fields to non-default values.
message.optional_int32 = 5
@ -1363,6 +1406,9 @@ class Proto2Test(unittest.TestCase):
self.assertFalse(message.HasField('optional_int32'))
self.assertFalse(message.HasField('optional_bool'))
self.assertFalse(message.HasField('optional_nested_message'))
self.assertNotIn('optional_int32', message)
self.assertNotIn('optional_bool', message)
self.assertNotIn('optional_nested_message', message)
self.assertEqual(0, message.optional_int32)
self.assertEqual(False, message.optional_bool)
self.assertEqual(0, message.optional_nested_message.bb)
@ -1689,6 +1735,12 @@ class Proto3Test(unittest.TestCase):
with self.assertRaises(ValueError):
message.HasField('repeated_nested_message')
# Can not test "in" operator.
with self.assertRaises(ValueError):
'repeated_int32' in message
with self.assertRaises(ValueError):
'repeated_nested_message' in message
# Fields should default to their type-specific default.
self.assertEqual(0, message.optional_int32)
self.assertEqual(0, message.optional_float)
@ -1699,6 +1751,7 @@ class Proto3Test(unittest.TestCase):
# Setting a submessage should still return proper presence information.
message.optional_nested_message.bb = 0
self.assertTrue(message.HasField('optional_nested_message'))
self.assertIn('optional_nested_message', message)
# Set the fields to non-default values.
message.optional_int32 = 5

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save