Skip to content

Commit

Permalink
CL-Protobufs now supports editions, so let the outside world use it.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 699386274
  • Loading branch information
Jonathan Godbout authored and copybara-github committed Nov 26, 2024
1 parent 0244ecb commit 026c5f1
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 4 deletions.
12 changes: 10 additions & 2 deletions cl-protobufs.asd
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,8 @@ and functionality for working with them."
:serial t
:pathname ""
:depends-on ("google-tests-proto")
:components ((:file "packed-test")))
:components ((:protobuf-source-file "editions-2023")
(:file "packed-test")))

(:module "serialize-to-bytes-test"
:serial t
Expand Down Expand Up @@ -348,6 +349,13 @@ and functionality for working with them."
:proto-pathname "deep-import/deep-import-test-3.proto")
(:protobuf-source-file "deep-import-proto"
:proto-search-path ("deep-import/"))
(:file "deep-import-test"))))
(:file "deep-import-test")))
(:module "import-test-with-editions"
:serial t
:pathname ""
:depends-on ("root-suite")
:components ((:protobuf-source-file "import-proto-with-editions")
(:protobuf-source-file "editions-2023")
(:file "import-test-with-editions"))))
:perform (test-op (o c)
(uiop:symbol-call '#:cl-protobufs.test '#:run-all)))
11 changes: 10 additions & 1 deletion protoc/generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <vector>

#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/descriptor.pb.h>

namespace google {
class FileDescriptor;
Expand Down Expand Up @@ -41,7 +42,15 @@ class LispGenerator : public compiler::CodeGenerator {

// cl-protobufs supports proto3 optional fields.
uint64_t GetSupportedFeatures() const override {
return FEATURE_PROTO3_OPTIONAL;
return FEATURE_PROTO3_OPTIONAL | FEATURE_SUPPORTS_EDITIONS;
}

Edition GetMinimumEdition() const override {
return Edition::EDITION_PROTO2;
}

Edition GetMaximumEdition() const override {
return Edition::EDITION_2023;
}

private:
Expand Down
40 changes: 40 additions & 0 deletions tests/editions-2023.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Edition version of proto2 file
edition = "2023";

package com.example;

option features.field_presence = EXPLICIT;
option features.repeated_field_encoding = PACKED;

message Food {
string name = 1;
}

message Drink {
string name = 1;
}


message Player {
// fields have explicit presence, so no explicit setting needed
string name = 1;
// to match the proto2 behavior, LEGACY_REQUIRED is set at the field level
// int32 id = 2 [features.field_presence = LEGACY_REQUIRED];
// to match the proto2 behavior, EXPANDED is set at the field level
repeated int32 scores = 3 [features.repeated_field_encoding = EXPANDED];
repeated int32 packed_scores = 4;

enum Handed {
HANDED_UNSPECIFIED = 0;
HANDED_LEFT = 1;
HANDED_RIGHT = 2;
HANDED_AMBIDEXTROUS = 3;
}

Handed handed = 5 [features.field_presence = IMPLICIT];
int32 faye = 6;
Food lunch = 7 [features.message_encoding = DELIMITED];
Drink lunch_drink = 8;

reserved gender;
}
19 changes: 19 additions & 0 deletions tests/import-proto-with-editions.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2024 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

syntax = "proto2";

package third_party.lisp.cl_protobufs.tests;

import "import-test-import-1.proto"; // Test proto
import "import-test-import-2.proto"; // Test proto
import "editions-2023.proto"; // Test proto

message ImportTestEdition {
optional Import1 import1 = 1;
optional Import2 import2 = 2;
optional com.example.Player player = 3;
}
99 changes: 99 additions & 0 deletions tests/import-test-with-editions.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
;;; Copyright 2020 Google LLC
;;;
;;; Use of this source code is governed by an MIT-style
;;; license that can be found in the LICENSE file or at
;;; https://opensource.org/licenses/MIT.

(defpackage #:cl-protobufs.test.import
(:use #:cl
#:clunit
#:cl-protobufs.com.example)
(:local-nicknames (#:pb #:cl-protobufs.third-party.lisp.cl-protobufs.tests)
(#:pi #:cl-protobufs.implementation))
(:export :run))

(in-package #:cl-protobufs.test.import)


(defsuite import-edition-suite (cl-protobufs.test:root-suite))

(defun run (&key use-debugger)
"Run all tests in the test suite.
Parameters
USE-DEBUGGER: On assert failure bring up the debugger."
(clunit:run-suite 'import-edition-suite :use-debugger use-debugger
:signal-condition-on-fail t))

(deftest test-all-imports-are-included (import-edition-suite)
(let* ((descriptor (cl-protobufs:find-file-descriptor 'pb:import-proto-with-editions))
(imports (pi::proto-imports descriptor)))
(assert-eql 3 (length imports))
(print (first imports))
(print (second imports))
(print (third imports))
(assert-true (search "import-test-import-1.proto" (first imports)))
(assert-true (search "import-test-import-2.proto" (second imports)))
(assert-true (search "editions-2023.proto" (third imports)))))

(deftest field-presence-test (import-edition-suite)
(let ((player (make-player)))
(assert-false (player.has-name player))
(setf (player.name player) "lyra")
(assert-true (player.has-name player))
(player.clear-name player)
(assert-false (player.has-name player))

;; Since the field is implicit we need to use
;; the internal has function
(assert-false (cl-protobufs.com.example::player.%%has-handed player))
(setf (player.handed player) :handed-unspecified)
(assert-false (cl-protobufs.com.example::player.%%has-handed player))
(setf (player.handed player) :handed-right)
(assert-true (cl-protobufs.com.example::player.%%has-handed player))
(setf (player.handed player) :handed-unspecified)
(assert-false (cl-protobufs.com.example::player.%%has-handed player))
(setf (player.handed player) :handed-right)
(assert-true (cl-protobufs.com.example::player.%%has-handed player))
(player.clear-handed player)
(assert-false (cl-protobufs.com.example::player.%%has-handed player))))

(deftest protoc-message-encoding-delimited-gives-kind (import-edition-suite)
(let* ((player-descriptor (cl-protobufs:find-message-descriptor
'player))
(lunch-drink-descriptor (cl-protobufs:find-field-descriptor
player-descriptor
'lunch-drink)))
(assert-eql (cl-protobufs:proto-kind lunch-drink-descriptor) :message)))

(deftest read-edition-messages-in-text-format (import-edition-suite)
(let ((hand-made-message
(make-player :name "Lyra"
:scores '(1 2 3)
:packed-scores '(4 5 6)
:handed :handed-left
:faye 3
:lunch (make-food :name "Cinnamon Roll")
:lunch-drink (make-drink :name "Hot Chocolate")))
(msg (cl-protobufs:parse-text-format
'player
:stream (make-string-input-stream "
name: 'Lyra'
scores: [1,2,3]
packed_scores: [4,5,6]
handed: HANDED_LEFT
faye: 3
lunch: {
name: 'Cinnamon Roll'
}
lunch_drink: {
name: 'Hot Chocolate'
}"))))
(assert-true
(cl-protobufs:proto-equal msg hand-made-message :exact t))
(let ((round-trip-message
(cl-protobufs:parse-text-format
'player
:stream (make-string-input-stream
(format nil "~@/cl-protobufs:fmt/" msg)))))
(assert-true
(cl-protobufs:proto-equal msg round-trip-message :exact t)))))
2 changes: 1 addition & 1 deletion tests/packed-test.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Parameters
(assert-eql #b10010 (pi::packed-tag 2))
(assert-eql #b11010 (pi::packed-tag 3)))

#+nil(deftest packed-encoding-test-2023 (packed-suite)
(deftest packed-encoding-test-2023 (packed-suite)
(let ((player (cl-protobufs.com.example:make-player)))
(push 10 (cl-protobufs.com.example:packed-scores player))
(push 20 (cl-protobufs.com.example:packed-scores player))
Expand Down

0 comments on commit 026c5f1

Please sign in to comment.