Google-ProtocolBuffers-0.12/000755 000765 000024 00000000000 12773222075 015734 5ustar00wesstaff000000 000000 Google-ProtocolBuffers-0.12/bin/000755 000765 000024 00000000000 12773222075 016504 5ustar00wesstaff000000 000000 Google-ProtocolBuffers-0.12/Changes000755 000765 000024 00000003104 12773222021 017217 0ustar00wesstaff000000 000000 Revision history for Perl extension Google::ProtocolBuffers 0.12 2016-09-29 - various makefile cleanups: https://github.com/csirtgadgets/google-protocolbuffers-perl/pull/22 0.11 2014- - bugfixes - bugfix to getExtension code, returns keylist when no arg is passed through 0.11 2013-12-29 - bugfixes - doc fix for -p option 0.10 2013-11-20 - bugfixes: - use perl 5.8, constants break on 5.6 - features: - created protoc-perl 0.09 2013-11-07 - bugfixes: - parser (floating point literals, FloatLit in Compiler.pm) - parser fix for fp in CodeGen.pm - features: - decoding of packed repeated fields - package_name for code generator - allow for package line generation in generated module - accept multiple include_dir as an arrayref - accept 'no_timestamp' argument to parse 0.08 Thu Oct 23 21:45:03 MSD 2008 - Fixed encoding/decoding of float types on big-endian machines - Fixed default strings values with characters > 127 - Added dependencies on Perl v5.6.0 (for 'our'), 'constant' v1.06 (for multiple constants declaration) and 'Test::More' v0.52 (for correct require_ok() in tests) 0.06 Wed Oct 22 00:12:58 2008 - Typos in documentation were fixed, public CPAN release 0.05_01 Tue Oct 21 01:06:17 2008 - first (alpha) release for CPAN 0.01 Wed Oct 8 22:15:12 2008 - original version; created by h2xs 1.23 with options -X Google::ProtoBuf Google-ProtocolBuffers-0.12/lib/000755 000765 000024 00000000000 12773222075 016502 5ustar00wesstaff000000 000000 Google-ProtocolBuffers-0.12/Makefile.PL000644 000765 000024 00000002425 12773221061 017703 0ustar00wesstaff000000 000000 use 5.006; use strict; use warnings FATAL => 'all'; use ExtUtils::MakeMaker; WriteMakefile( NAME => 'Google::ProtocolBuffers', AUTHOR => 'Igor Gariev , the CISRT Gadgets Foundation ', ABSTRACT_FROM => 'lib/Google/ProtocolBuffers.pm', VERSION_FROM => 'lib/Google/ProtocolBuffers.pm', LICENSE => 'PERL', EXE_FILES => ['bin/protoc-perl'], MIN_PERL_VERSION => 5.012, CONFIGURE_REQUIRES => { 'ExtUtils::MakeMaker' => 0, }, BUILD_REQUIRES => { 'Test::More' => 0.52, }, 'META_MERGE' => { "resources" => { "repository" => 'https://github.com/csirtgadgets/google-protocolbuffers-perl.git', "bugtracker" => 'https://github.com/csirtgadgets/google-protocolbuffers-perl/issues', "homepage" => 'https://github.com/csirtgadgets/google-protocolbuffers-perl', }, }, PREREQ_PM => { 'Parse::RecDescent' => 1.94, 'Test::More' => 0.52, 'Math::BigInt' => 0, 'Class::Accessor' => 0, 'constant' => 0, 'Config' => 0, }, dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', }, clean => { FILES => 'test-*' }, ); Google-ProtocolBuffers-0.12/MANIFEST000644 000765 000024 00000001510 12773222075 017062 0ustar00wesstaff000000 000000 bin/protoc-perl Changes lib/Google/ProtocolBuffers.pm lib/Google/ProtocolBuffers/Codec.pm lib/Google/ProtocolBuffers/CodecIV32.pm lib/Google/ProtocolBuffers/CodecIV64.pm lib/Google/ProtocolBuffers/CodeGen.pm lib/Google/ProtocolBuffers/Compiler.pm lib/Google/ProtocolBuffers/Constants.pm Makefile.PL MANIFEST This list of files README README.md t/01-load.t t/02-compiler.t t/03-encoder.t t/04-decoder.t t/05-enums.t t/06-accessors.t t/07-extensions.t t/08-defaults.t t/09-codegen-a.t t/10-codegen-b.t t/11-broken.t t/12-unknown.t t/13-native64.t t/14-oneof.t t/bootstrap.pl t/extra/enumalias.proto t/google/protobuf/unittest.proto t/google/protobuf/unittest_import.proto META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Google-ProtocolBuffers-0.12/META.json000644 000765 000024 00000002717 12773222075 017364 0ustar00wesstaff000000 000000 { "abstract" : "simple interface to Google Protocol Buffers", "author" : [ "Igor Gariev , the CISRT Gadgets Foundation " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.04, CPAN::Meta::Converter version 2.143240", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Google-ProtocolBuffers", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "Test::More" : "0.52" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Class::Accessor" : "0", "Config" : "0", "Math::BigInt" : "0", "Parse::RecDescent" : "1.94", "Test::More" : "0.52", "constant" : "0", "perl" : "5.012" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/csirtgadgets/google-protocolbuffers-perl/issues" }, "homepage" : "https://github.com/csirtgadgets/google-protocolbuffers-perl", "repository" : { "url" : "https://github.com/csirtgadgets/google-protocolbuffers-perl.git" } }, "version" : "0.12" } Google-ProtocolBuffers-0.12/META.yml000644 000765 000024 00000001640 12773222075 017206 0ustar00wesstaff000000 000000 --- abstract: 'simple interface to Google Protocol Buffers' author: - 'Igor Gariev , the CISRT Gadgets Foundation ' build_requires: Test::More: '0.52' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.04, CPAN::Meta::Converter version 2.143240' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Google-ProtocolBuffers no_index: directory: - t - inc requires: Class::Accessor: '0' Config: '0' Math::BigInt: '0' Parse::RecDescent: '1.94' Test::More: '0.52' constant: '0' perl: '5.012' resources: bugtracker: https://github.com/csirtgadgets/google-protocolbuffers-perl/issues homepage: https://github.com/csirtgadgets/google-protocolbuffers-perl repository: https://github.com/csirtgadgets/google-protocolbuffers-perl.git version: '0.12' Google-ProtocolBuffers-0.12/README000755 000765 000024 00000001715 12773206454 016626 0ustar00wesstaff000000 000000 Google-ProtocolBuffers ====================== Google Protocol Buffers is a data serialization format. It is binary (and hence compact and fast for serialization) and as extendable as XML; its nearest analogues are Thrift and ASN.1. There are official mappings for C++, Java and Python languages; this library is a mapping for Perl. INSTALLATION To install this module type the following: perl Makefile.PL make make test make install DEPENDENCIES This module requires these other modules and libraries: Parse::RecDescent Math::BigInt Class::Accessor COPYRIGHT AND LICENCE Copyright (C) 2012 by Igor Gariev, Copyright (C) 2013 by the CSIRT Gadgets Foundation This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.10.0 or, at your option, any later version of Perl 5 you may have available. Google-ProtocolBuffers-0.12/README.md000644 000765 000024 00000002117 12773206454 017217 0ustar00wesstaff000000 000000 Google-ProtocolBuffers == [![Build Status](https://travis-ci.org/csirtgadgets/google-protocolbuffers-perl.png?branch=stable)](https://travis-ci.org/csirtgadgets/google-protocolbuffers-perl) Google Protocol Buffers is a data serialization format. It is binary (and hence compact and fast for serialization) and as extendable as XML; its nearest analogues are Thrift and ASN.1. There are official mappings for C++, Java and Python languages; this library is a mapping for Perl. INSTALLATION To install this module type the following: ``` perl Makefile.PL make make test make install ``` DEPENDENCIES This module requires these other modules and libraries: ``` Parse::RecDescent Math::BigInt Class::Accessor ``` COPYRIGHT AND LICENCE ``` Copyright (C) 2008 by Igor Gariev, Copyright (C) 2013 by the CSIRT Gadgets Foundation ``` This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.10.0 or, at your option, any later version of Perl 5 you may have available. Google-ProtocolBuffers-0.12/t/000755 000765 000024 00000000000 12773222075 016177 5ustar00wesstaff000000 000000 Google-ProtocolBuffers-0.12/t/01-load.t000755 000765 000024 00000000776 12773206454 017541 0ustar00wesstaff000000 000000 # Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl Google-ProtocolBuffers.t' ######################### # change 'tests => 1' to 'tests => last_test_to_print'; use Test::More tests => 1; BEGIN { use_ok('Google::ProtocolBuffers') }; ######################### # Insert your test code below, the Test::More module is use()ed here so read # its man page ( perldoc Test::More ) for help writing this test script. Google-ProtocolBuffers-0.12/t/02-compiler.t000755 000765 000024 00000002331 12773206454 020422 0ustar00wesstaff000000 000000 use Test::More tests => 7; use Carp; use strict; use Google::ProtocolBuffers; BEGIN{ $SIG{__DIE__} = \&Carp::confess; } my @classes; @classes = Google::ProtocolBuffers->parse("package my.test_case; message A{}"); is(scalar @classes, 1); is($classes[0], 'My::TestCase::A'); @classes = Google::ProtocolBuffers->parse( "package my.test_case; message B{}", {no_camel_case => 1} ); is(scalar @classes, 1); is($classes[0], 'my::test_case::B'); @classes = Google::ProtocolBuffers->parse(" message Person { required string name = 1; required int32 id = 2; // Unique ID number for this person. optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phone = 4; } "); is(scalar(@classes), 3); @classes = sort @classes; is_deeply(\@classes, ['Person', 'Person::PhoneNumber', 'Person::PhoneType']); @classes = Google::ProtocolBuffers->parsefile("google/protobuf/unittest.proto", {include_dir => 't'}); is(scalar(@classes), 35); Google-ProtocolBuffers-0.12/t/03-encoder.t000755 000765 000024 00000075246 12773206454 020247 0ustar00wesstaff000000 000000 use Test::More tests => 168; use strict; use warnings; use Google::ProtocolBuffers; use Math::BigInt; BEGIN{ $SIG{__DIE__} = \&Carp::confess; } Google::ProtocolBuffers->parsefile( "google/protobuf/unittest.proto", { include_dir => 't' } ); my $str; ## ## optional_int32 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_int32 => 0}); is($str, "\x{08}\x{00}", "optional_int32=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int32 => 1}); is($str, "\x{08}\x{01}", "optional_int32=1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int32 => -1}); is($str, "\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}", "optional_int32=-1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int32 => 2}); is($str, "\x{08}\x{02}", "optional_int32=2"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int32 => 23424}); is($str, "\x{08}\x{80}\x{b7}\x{01}", "optional_int32=23424"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int32 => 2147483647}); is($str, "\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{07}", "optional_int32=2147483647"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int32 => -2147483648}); is($str, "\x{08}\x{80}\x{80}\x{80}\x{80}\x{f8}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}", "optional_int32=-2147483648"); ## ## optional_int64 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_int64 => 0}); is($str, "\x{10}\x{00}", "optional_int64=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int64 => 1}); is($str, "\x{10}\x{01}", "optional_int64=1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int64 => -1}); is($str, "\x{10}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}", "optional_int64=-1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int64 => Math::BigInt->new("234234234234")}); is($str, "\x{10}\x{fa}\x{8a}\x{cb}\x{cb}\x{e8}\x{06}", "optional_int64=Math::BigInt->new(\\x{22}234234234234\\x{22})"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int64 => Math::BigInt->new("9223372036854775807")}); is($str, "\x{10}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{7f}", "optional_int64=Math::BigInt->new(\\x{22}9223372036854775807\\x{22})"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int64 => Math::BigInt->new("-9223372036854775808")}); is($str, "\x{10}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{01}", "optional_int64=Math::BigInt->new(\\x{22}-9223372036854775808\\x{22})"); ## ## optional_uint32 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_uint32 => 0}); is($str, "\x{18}\x{00}", "optional_uint32=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_uint32 => 1}); is($str, "\x{18}\x{01}", "optional_uint32=1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_uint32 => 2}); is($str, "\x{18}\x{02}", "optional_uint32=2"); $str = ProtobufUnittest::TestAllTypes->encode({optional_uint32 => 2374234}); is($str, "\x{18}\x{da}\x{f4}\x{90}\x{01}", "optional_uint32=2374234"); $str = ProtobufUnittest::TestAllTypes->encode({optional_uint32 => 4294967295}); is($str, "\x{18}\x{ff}\x{ff}\x{ff}\x{ff}\x{0f}", "optional_uint32=4294967295"); ## ## optional_uint64 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_uint64 => 0}); is($str, "\x{20}\x{00}", "optional_uint64=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_uint64 => 1}); is($str, "\x{20}\x{01}", "optional_uint64=1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_uint64 => 2}); is($str, "\x{20}\x{02}", "optional_uint64=2"); $str = ProtobufUnittest::TestAllTypes->encode({optional_uint64 => Math::BigInt->new("2336346474234")}); is($str, "\x{20}\x{fa}\x{8d}\x{e8}\x{c8}\x{ff}C", "optional_uint64=Math::BigInt->new(\\x{22}2336346474234\\x{22})"); $str = ProtobufUnittest::TestAllTypes->encode({optional_uint64 => Math::BigInt->new("18446744073709551615")}); is($str, "\x{20}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}", "optional_uint64=Math::BigInt->new(\\x{22}18446744073709551615\\x{22})"); ## ## optional_sint32 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_sint32 => 0}); is($str, "\x{28}\x{00}", "optional_sint32=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint32 => 1}); is($str, "\x{28}\x{02}", "optional_sint32=1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint32 => -1}); is($str, "\x{28}\x{01}", "optional_sint32=-1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint32 => 2}); is($str, "\x{28}\x{04}", "optional_sint32=2"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint32 => 237374}); is($str, "\x{28}\x{fc}\x{fc}\x{1c}", "optional_sint32=237374"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint32 => -4858558}); is($str, "\x{28}\x{fb}\x{8a}\x{d1}\x{04}", "optional_sint32=-4858558"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint32 => 2147483647}); is($str, "\x{28}\x{fe}\x{ff}\x{ff}\x{ff}\x{0f}", "optional_sint32=2147483647"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint32 => -2147483648}); is($str, "\x{28}\x{ff}\x{ff}\x{ff}\x{ff}\x{0f}", "optional_sint32=-2147483648"); ## ## optional_sint64 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_sint64 => 0}); is($str, "0\x{00}", "optional_sint64=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint64 => 1}); is($str, "0\x{02}", "optional_sint64=1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint64 => -1}); is($str, "0\x{01}", "optional_sint64=-1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint64 => 2}); is($str, "0\x{04}", "optional_sint64=2"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint64 => Math::BigInt->new("234234234234")}); is($str, "0\x{f4}\x{95}\x{96}\x{97}\x{d1}\x{0d}", "optional_sint64=Math::BigInt->new(\\x{22}234234234234\\x{22})"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint64 => Math::BigInt->new("9223372036854775807")}); is($str, "0\x{fe}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}", "optional_sint64=Math::BigInt->new(\\x{22}9223372036854775807\\x{22})"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint64 => Math::BigInt->new("-9223372036854775808")}); is($str, "0\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}", "optional_sint64=Math::BigInt->new(\\x{22}-9223372036854775808\\x{22})"); ## ## optional_fixed32 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed32 => 0}); is($str, "\x{3d}\x{00}\x{00}\x{00}\x{00}", "optional_fixed32=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed32 => 1}); is($str, "\x{3d}\x{01}\x{00}\x{00}\x{00}", "optional_fixed32=1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed32 => 2}); is($str, "\x{3d}\x{02}\x{00}\x{00}\x{00}", "optional_fixed32=2"); $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed32 => 1453468424}); is($str, "\x{3d}\x{08}\x{2b}\x{a2}V", "optional_fixed32=1453468424"); $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed32 => 2147483647}); is($str, "\x{3d}\x{ff}\x{ff}\x{ff}\x{7f}", "optional_fixed32=2147483647"); $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed32 => 4294967295}); is($str, "\x{3d}\x{ff}\x{ff}\x{ff}\x{ff}", "optional_fixed32=4294967295"); ## ## optional_fixed64 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed64 => 0}); is($str, "A\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}", "optional_fixed64=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed64 => 1}); is($str, "A\x{01}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}", "optional_fixed64=1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed64 => 2}); is($str, "A\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}", "optional_fixed64=2"); $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed64 => Math::BigInt->new("234234234234")}); is($str, "Az\x{c5}r\x{89}6\x{00}\x{00}\x{00}", "optional_fixed64=Math::BigInt->new(\\x{22}234234234234\\x{22})"); $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed64 => Math::BigInt->new("9223372036854775807")}); is($str, "A\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{7f}", "optional_fixed64=Math::BigInt->new(\\x{22}9223372036854775807\\x{22})"); $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed64 => Math::BigInt->new("18446744073709551615")}); is($str, "A\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}", "optional_fixed64=Math::BigInt->new(\\x{22}18446744073709551615\\x{22})"); ## ## optional_sfixed32 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed32 => 0}); is($str, "M\x{00}\x{00}\x{00}\x{00}", "optional_sfixed32=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed32 => 1}); is($str, "M\x{01}\x{00}\x{00}\x{00}", "optional_sfixed32=1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed32 => -1}); is($str, "M\x{ff}\x{ff}\x{ff}\x{ff}", "optional_sfixed32=-1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed32 => 2}); is($str, "M\x{02}\x{00}\x{00}\x{00}", "optional_sfixed32=2"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed32 => 1130468424}); is($str, "MH\x{94}aC", "optional_sfixed32=1130468424"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed32 => 2147483647}); is($str, "M\x{ff}\x{ff}\x{ff}\x{7f}", "optional_sfixed32=2147483647"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed32 => -2147483648}); is($str, "M\x{00}\x{00}\x{00}\x{80}", "optional_sfixed32=-2147483648"); ## ## optional_sfixed64 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed64 => 0}); is($str, "Q\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}", "optional_sfixed64=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed64 => 1}); is($str, "Q\x{01}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}", "optional_sfixed64=1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed64 => -1}); is($str, "Q\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}", "optional_sfixed64=-1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed64 => 2}); is($str, "Q\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}", "optional_sfixed64=2"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed64 => Math::BigInt->new("234234234234")}); is($str, "Qz\x{c5}r\x{89}6\x{00}\x{00}\x{00}", "optional_sfixed64=Math::BigInt->new(\\x{22}234234234234\\x{22})"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed64 => Math::BigInt->new("9223372036854775807")}); is($str, "Q\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{7f}", "optional_sfixed64=Math::BigInt->new(\\x{22}9223372036854775807\\x{22})"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed64 => Math::BigInt->new("-9223372036854775808")}); is($str, "Q\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{80}", "optional_sfixed64=Math::BigInt->new(\\x{22}-9223372036854775808\\x{22})"); ## ## optional_float ## $str = ProtobufUnittest::TestAllTypes->encode({optional_float => 0}); is($str, "\x{5d}\x{00}\x{00}\x{00}\x{00}", "optional_float=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_float => 1}); is($str, "\x{5d}\x{00}\x{00}\x{80}\x{3f}", "optional_float=1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_float => 0.5}); is($str, "\x{5d}\x{00}\x{00}\x{00}\x{3f}", "optional_float=0.5"); $str = ProtobufUnittest::TestAllTypes->encode({optional_float => -0.5}); is($str, "\x{5d}\x{00}\x{00}\x{00}\x{bf}", "optional_float=-0.5"); $str = ProtobufUnittest::TestAllTypes->encode({optional_float => 10000000000}); is($str, "\x{5d}\x{f9}\x{02}\x{15}P", "optional_float=10000000000"); $str = ProtobufUnittest::TestAllTypes->encode({optional_float => -1e+020}); is($str, "\x{5d}\x{ec}x\x{ad}\x{e0}", "optional_float=-1e+020"); $str = ProtobufUnittest::TestAllTypes->encode({optional_float => 1e-010}); is($str, "\x{5d}\x{ff}\x{e6}\x{db}\x{2e}", "optional_float=1e-010"); $str = ProtobufUnittest::TestAllTypes->encode({optional_float => -2e-020}); is($str, "\x{5d}\x{08}\x{e5}\x{bc}\x{9e}", "optional_float=-2e-020"); ## ## optional_double ## $str = ProtobufUnittest::TestAllTypes->encode({optional_double => 0}); is($str, "a\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}", "optional_double=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_double => 1}); is($str, "a\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{f0}\x{3f}", "optional_double=1"); $str = ProtobufUnittest::TestAllTypes->encode({optional_double => 0.5}); is($str, "a\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{e0}\x{3f}", "optional_double=0.5"); $str = ProtobufUnittest::TestAllTypes->encode({optional_double => -0.5}); is($str, "a\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{e0}\x{bf}", "optional_double=-0.5"); $str = ProtobufUnittest::TestAllTypes->encode({optional_double => 10000000000}); is($str, "a\x{00}\x{00}\x{00}\x{20}_\x{a0}\x{02}B", "optional_double=10000000000"); $str = ProtobufUnittest::TestAllTypes->encode({optional_double => -1e+020}); is($str, "a\x{40}\x{8c}\x{b5}x\x{1d}\x{af}\x{15}\x{c4}", "optional_double=-1e+020"); $str = ProtobufUnittest::TestAllTypes->encode({optional_double => 1e-010}); is($str, "a\x{bb}\x{bd}\x{d7}\x{d9}\x{df}\x{7c}\x{db}\x{3d}", "optional_double=1e-010"); $str = ProtobufUnittest::TestAllTypes->encode({optional_double => -2e-020}); is($str, "a\x{23}B\x{92}\x{0c}\x{a1}\x{9c}\x{d7}\x{bb}", "optional_double=-2e-020"); $str = ProtobufUnittest::TestAllTypes->encode({optional_double => 1e-040}); is($str, "a\x{9c}Ww\x{27}\x{26}l\x{a1}7", "optional_double=1e-040"); $str = ProtobufUnittest::TestAllTypes->encode({optional_double => 1e+050}); is($str, "a\x{9a}d\x{7e}\x{c5}\x{0e}\x{1b}QJ", "optional_double=1e+050"); ## ## optional_bool ## $str = ProtobufUnittest::TestAllTypes->encode({optional_bool => 0}); is($str, "h\x{00}", "optional_bool=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_bool => 1}); is($str, "h\x{01}", "optional_bool=1"); ## ## optional_string ## $str = ProtobufUnittest::TestAllTypes->encode({optional_string => ""}); is($str, "r\x{00}", "optional_string=\\x{22}\\x{22}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_string => "\x{09}"}); is($str, "r\x{01}\x{09}", "optional_string=\\x{22}\\x{5c}x{09}\\x{22}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_string => "\x{0a}"}); is($str, "r\x{01}\x{0a}", "optional_string=\\x{22}\\x{5c}x{0a}\\x{22}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_string => "\x{0d}"}); is($str, "r\x{01}\x{0d}", "optional_string=\\x{22}\\x{5c}x{0d}\\x{22}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_string => "Hello\x{2c}\x{20}world"}); is($str, "r\x{0c}Hello\x{2c}\x{20}world", "optional_string=\\x{22}Hello\\x{5c}x{2c}\\x{5c}x{20}world\\x{22}"); ## ## optional_bytes ## $str = ProtobufUnittest::TestAllTypes->encode({optional_bytes => ""}); is($str, "z\x{00}", "optional_bytes=\\x{22}\\x{22}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_bytes => "\x{00}"}); is($str, "z\x{01}\x{00}", "optional_bytes=\\x{22}\\x{5c}x{00}\\x{22}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_bytes => "Hello\x{2c}\x{20}world"}); is($str, "z\x{0c}Hello\x{2c}\x{20}world", "optional_bytes=\\x{22}Hello\\x{5c}x{2c}\\x{5c}x{20}world\\x{22}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_bytes => "\x{ff}\x{fe}\x{fd}"}); is($str, "z\x{03}\x{ff}\x{fe}\x{fd}", "optional_bytes=\\x{22}\\x{5c}x{ff}\\x{5c}x{fe}\\x{5c}x{fd}\\x{22}"); ## ## OptionalGroup ## $str = ProtobufUnittest::TestAllTypes->encode({OptionalGroup => {a => 0}}); is($str, "\x{83}\x{01}\x{88}\x{01}\x{00}\x{84}\x{01}", "OptionalGroup={a => 0}"); $str = ProtobufUnittest::TestAllTypes->encode({OptionalGroup => {a => -1}}); is($str, "\x{83}\x{01}\x{88}\x{01}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}\x{84}\x{01}", "OptionalGroup={a => -1}"); $str = ProtobufUnittest::TestAllTypes->encode({OptionalGroup => {a => 199}}); is($str, "\x{83}\x{01}\x{88}\x{01}\x{c7}\x{01}\x{84}\x{01}", "OptionalGroup={a => 199}"); ## ## optional_nested_message ## $str = ProtobufUnittest::TestAllTypes->encode({optional_nested_message => {bb => 0}}); is($str, "\x{92}\x{01}\x{02}\x{08}\x{00}", "optional_nested_message={bb => 0}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_nested_message => {bb => 1}}); is($str, "\x{92}\x{01}\x{02}\x{08}\x{01}", "optional_nested_message={bb => 1}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_nested_message => {bb => -1}}); is($str, "\x{92}\x{01}\x{0b}\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}", "optional_nested_message={bb => -1}"); ## ## optional_foreign_message ## $str = ProtobufUnittest::TestAllTypes->encode({optional_foreign_message => {c => 0}}); is($str, "\x{9a}\x{01}\x{02}\x{08}\x{00}", "optional_foreign_message={c => 0}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_foreign_message => {c => -1}}); is($str, "\x{9a}\x{01}\x{0b}\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}", "optional_foreign_message={c => -1}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_foreign_message => {c => 1}}); is($str, "\x{9a}\x{01}\x{02}\x{08}\x{01}", "optional_foreign_message={c => 1}"); ## ## optional_import_message ## $str = ProtobufUnittest::TestAllTypes->encode({optional_import_message => {d => 0}}); is($str, "\x{a2}\x{01}\x{02}\x{08}\x{00}", "optional_import_message={d => 0}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_import_message => {d => -1}}); is($str, "\x{a2}\x{01}\x{0b}\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}", "optional_import_message={d => -1}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_import_message => {d => 1}}); is($str, "\x{a2}\x{01}\x{02}\x{08}\x{01}", "optional_import_message={d => 1}"); ## ## optional_nested_enum ## $str = ProtobufUnittest::TestAllTypes->encode({optional_nested_enum => ProtobufUnittest::TestAllTypes::NestedEnum::FOO()}); is($str, "\x{a8}\x{01}\x{01}", "optional_nested_enum:FOO"); $str = ProtobufUnittest::TestAllTypes->encode({optional_nested_enum => ProtobufUnittest::TestAllTypes::NestedEnum::BAR()}); is($str, "\x{a8}\x{01}\x{02}", "optional_nested_enum:BAR"); $str = ProtobufUnittest::TestAllTypes->encode({optional_nested_enum => ProtobufUnittest::TestAllTypes::NestedEnum::BAZ()}); is($str, "\x{a8}\x{01}\x{03}", "optional_nested_enum:BAZ"); ## ## optional_foreign_enum ## $str = ProtobufUnittest::TestAllTypes->encode({optional_foreign_enum => ProtobufUnittest::ForeignEnum::FOREIGN_FOO()}); is($str, "\x{b0}\x{01}\x{04}", "optional_foreign_enum:FOREIGN_FOO"); $str = ProtobufUnittest::TestAllTypes->encode({optional_foreign_enum => ProtobufUnittest::ForeignEnum::FOREIGN_BAR()}); is($str, "\x{b0}\x{01}\x{05}", "optional_foreign_enum:FOREIGN_BAR"); $str = ProtobufUnittest::TestAllTypes->encode({optional_foreign_enum => ProtobufUnittest::ForeignEnum::FOREIGN_BAZ()}); is($str, "\x{b0}\x{01}\x{06}", "optional_foreign_enum:FOREIGN_BAZ"); ## ## optional_import_enum ## $str = ProtobufUnittest::TestAllTypes->encode({optional_import_enum => ProtobufUnittestImport::ImportEnum::IMPORT_FOO()}); is($str, "\x{b8}\x{01}\x{07}", "optional_import_enum:IMPORT_FOO"); $str = ProtobufUnittest::TestAllTypes->encode({optional_import_enum => ProtobufUnittestImport::ImportEnum::IMPORT_BAR()}); is($str, "\x{b8}\x{01}\x{08}", "optional_import_enum:IMPORT_BAR"); $str = ProtobufUnittest::TestAllTypes->encode({optional_import_enum => ProtobufUnittestImport::ImportEnum::IMPORT_BAZ()}); is($str, "\x{b8}\x{01}\x{09}", "optional_import_enum:IMPORT_BAZ"); ## ## optional_string_piece ## $str = ProtobufUnittest::TestAllTypes->encode({optional_string_piece => ""}); is($str, "\x{c2}\x{01}\x{00}", "optional_string_piece=\\x{22}\\x{22}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_string_piece => "Hello\x{2c}\x{20}world"}); is($str, "\x{c2}\x{01}\x{0c}Hello\x{2c}\x{20}world", "optional_string_piece=\\x{22}Hello\\x{5c}x{2c}\\x{5c}x{20}world\\x{22}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_string_piece => "\x{0d}\x{09}\x{0a}"}); is($str, "\x{c2}\x{01}\x{03}\x{0d}\x{09}\x{0a}", "optional_string_piece=\\x{22}\\x{5c}x{0d}\\x{5c}x{09}\\x{5c}x{0a}\\x{22}"); ## ## optional_cord ## $str = ProtobufUnittest::TestAllTypes->encode({optional_cord => ""}); is($str, "\x{ca}\x{01}\x{00}", "optional_cord=\\x{22}\\x{22}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_cord => "Hello\x{2c}\x{20}world"}); is($str, "\x{ca}\x{01}\x{0c}Hello\x{2c}\x{20}world", "optional_cord=\\x{22}Hello\\x{5c}x{2c}\\x{5c}x{20}world\\x{22}"); $str = ProtobufUnittest::TestAllTypes->encode({optional_cord => "\x{0d}\x{09}\x{0a}"}); is($str, "\x{ca}\x{01}\x{03}\x{0d}\x{09}\x{0a}", "optional_cord=\\x{22}\\x{5c}x{0d}\\x{5c}x{09}\\x{5c}x{0a}\\x{22}"); ## ## repeated_int32 ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_int32 => 0}); is($str, "\x{f8}\x{01}\x{00}", "repeated_int32:0"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_int32 => [0]}); is($str, "\x{f8}\x{01}\x{00}", "repeated_int32=[0]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_int32 => [0, -1, 1]}); is($str, "\x{f8}\x{01}\x{00}\x{f8}\x{01}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}\x{f8}\x{01}\x{01}", "repeated_int32=[0, -1, 1]"); ## ## repeated_int64 ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_int64 => [0]}); is($str, "\x{80}\x{02}\x{00}", "repeated_int64=[0]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_int64 => [0, -1, 1]}); is($str, "\x{80}\x{02}\x{00}\x{80}\x{02}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}\x{80}\x{02}\x{01}", "repeated_int64=[0, -1, 1]"); ## ## repeated_uint32 ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_uint32 => [0]}); is($str, "\x{88}\x{02}\x{00}", "repeated_uint32=[0]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_uint32 => [0, 2, 1]}); is($str, "\x{88}\x{02}\x{00}\x{88}\x{02}\x{02}\x{88}\x{02}\x{01}", "repeated_uint32=[0, 2, 1]"); ## ## repeated_uint64 ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_uint64 => [0]}); is($str, "\x{90}\x{02}\x{00}", "repeated_uint64=[0]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_uint64 => [0, 2, 1]}); is($str, "\x{90}\x{02}\x{00}\x{90}\x{02}\x{02}\x{90}\x{02}\x{01}", "repeated_uint64=[0, 2, 1]"); ## ## repeated_sint32 ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_sint32 => [0]}); is($str, "\x{98}\x{02}\x{00}", "repeated_sint32=[0]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_sint32 => [0, -1, 1]}); is($str, "\x{98}\x{02}\x{00}\x{98}\x{02}\x{01}\x{98}\x{02}\x{02}", "repeated_sint32=[0, -1, 1]"); ## ## repeated_sint64 ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_sint64 => [0]}); is($str, "\x{a0}\x{02}\x{00}", "repeated_sint64=[0]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_sint64 => [0, -1, 1]}); is($str, "\x{a0}\x{02}\x{00}\x{a0}\x{02}\x{01}\x{a0}\x{02}\x{02}", "repeated_sint64=[0, -1, 1]"); ## ## repeated_fixed32 ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_fixed32 => [0]}); is($str, "\x{ad}\x{02}\x{00}\x{00}\x{00}\x{00}", "repeated_fixed32=[0]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_fixed32 => [0, 3, 1]}); is($str, "\x{ad}\x{02}\x{00}\x{00}\x{00}\x{00}\x{ad}\x{02}\x{03}\x{00}\x{00}\x{00}\x{ad}\x{02}\x{01}\x{00}\x{00}\x{00}", "repeated_fixed32=[0, 3, 1]"); ## ## repeated_fixed64 ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_fixed64 => [0]}); is($str, "\x{b1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}", "repeated_fixed64=[0]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_fixed64 => [0, 3, 1]}); is($str, "\x{b1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{b1}\x{02}\x{03}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{b1}\x{02}\x{01}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}", "repeated_fixed64=[0, 3, 1]"); ## ## repeated_sfixed32 ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_sfixed32 => [0]}); is($str, "\x{bd}\x{02}\x{00}\x{00}\x{00}\x{00}", "repeated_sfixed32=[0]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_sfixed32 => [0, -1, 1]}); is($str, "\x{bd}\x{02}\x{00}\x{00}\x{00}\x{00}\x{bd}\x{02}\x{ff}\x{ff}\x{ff}\x{ff}\x{bd}\x{02}\x{01}\x{00}\x{00}\x{00}", "repeated_sfixed32=[0, -1, 1]"); ## ## repeated_sfixed64 ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_sfixed64 => [0]}); is($str, "\x{c1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}", "repeated_sfixed64=[0]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_sfixed64 => [0, -1, 1]}); is($str, "\x{c1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{c1}\x{02}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{c1}\x{02}\x{01}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}", "repeated_sfixed64=[0, -1, 1]"); ## ## repeated_float ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_float => [0]}); is($str, "\x{cd}\x{02}\x{00}\x{00}\x{00}\x{00}", "repeated_float=[0]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_float => [0, -0.5, 10000000000]}); is($str, "\x{cd}\x{02}\x{00}\x{00}\x{00}\x{00}\x{cd}\x{02}\x{00}\x{00}\x{00}\x{bf}\x{cd}\x{02}\x{f9}\x{02}\x{15}P", "repeated_float=[0, -0.5, 10000000000]"); ## ## repeated_double ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_double => [0]}); is($str, "\x{d1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}", "repeated_double=[0]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_double => [0, -0.5, 10000000000]}); is($str, "\x{d1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{d1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{e0}\x{bf}\x{d1}\x{02}\x{00}\x{00}\x{00}\x{20}_\x{a0}\x{02}B", "repeated_double=[0, -0.5, 10000000000]"); ## ## repeated_bool ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_bool => [0]}); is($str, "\x{d8}\x{02}\x{00}", "repeated_bool=[0]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_bool => [0, 1, 1, 0]}); is($str, "\x{d8}\x{02}\x{00}\x{d8}\x{02}\x{01}\x{d8}\x{02}\x{01}\x{d8}\x{02}\x{00}", "repeated_bool=[0, 1, 1, 0]"); ## ## repeated_string ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_string => [""]}); is($str, "\x{e2}\x{02}\x{00}", "repeated_string=[\\x{22}\\x{22}]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_string => ["hello"]}); is($str, "\x{e2}\x{02}\x{05}hello", "repeated_string=[\\x{22}hello\\x{22}]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_string => ["hello", "world"]}); is($str, "\x{e2}\x{02}\x{05}hello\x{e2}\x{02}\x{05}world", "repeated_string=[\\x{22}hello\\x{22}, \\x{22}world\\x{22}]"); ## ## repeated_bytes ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_bytes => [""]}); is($str, "\x{ea}\x{02}\x{00}", "repeated_bytes=[\\x{22}\\x{22}]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_bytes => ["\x{00}"]}); is($str, "\x{ea}\x{02}\x{01}\x{00}", "repeated_bytes=[\\x{22}\\x{5c}x{00}\\x{22}]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_bytes => ["", "\x{00}", "\x{00}\x{00}"]}); is($str, "\x{ea}\x{02}\x{00}\x{ea}\x{02}\x{01}\x{00}\x{ea}\x{02}\x{02}\x{00}\x{00}", "repeated_bytes=[\\x{22}\\x{22}, \\x{22}\\x{5c}x{00}\\x{22}, \\x{22}\\x{5c}x{00}\\x{5c}x{00}\\x{22}]"); ## ## RepeatedGroup ## $str = ProtobufUnittest::TestAllTypes->encode({RepeatedGroup => [{a => 0}]}); is($str, "\x{f3}\x{02}\x{f8}\x{02}\x{00}\x{f4}\x{02}", "RepeatedGroup=[{a => 0}]"); $str = ProtobufUnittest::TestAllTypes->encode({RepeatedGroup => [{a => 0}, {a => -1}]}); is($str, "\x{f3}\x{02}\x{f8}\x{02}\x{00}\x{f4}\x{02}\x{f3}\x{02}\x{f8}\x{02}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}\x{f4}\x{02}", "RepeatedGroup=[{a => 0}, {a => -1}]"); ## ## repeated_nested_message ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_nested_message => [{bb => 0}]}); is($str, "\x{82}\x{03}\x{02}\x{08}\x{00}", "repeated_nested_message=[{bb => 0}]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_nested_message => [{bb => 1}, {bb => 2}]}); is($str, "\x{82}\x{03}\x{02}\x{08}\x{01}\x{82}\x{03}\x{02}\x{08}\x{02}", "repeated_nested_message=[{bb => 1}, {bb => 2}]"); ## ## repeated_foreign_message ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_foreign_message => [{c => 0}]}); is($str, "\x{8a}\x{03}\x{02}\x{08}\x{00}", "repeated_foreign_message=[{c => 0}]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_foreign_message => [{c => 0}, {c => -1}, {c => 1}]}); is($str, "\x{8a}\x{03}\x{02}\x{08}\x{00}\x{8a}\x{03}\x{0b}\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}\x{8a}\x{03}\x{02}\x{08}\x{01}", "repeated_foreign_message=[{c => 0}, {c => -1}, {c => 1}]"); ## ## repeated_import_message ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_import_message => [{d => 0}]}); is($str, "\x{92}\x{03}\x{02}\x{08}\x{00}", "repeated_import_message=[{d => 0}]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_import_message => [{d => 0}, {d => -1}, {d => 1}]}); is($str, "\x{92}\x{03}\x{02}\x{08}\x{00}\x{92}\x{03}\x{0b}\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}\x{92}\x{03}\x{02}\x{08}\x{01}", "repeated_import_message=[{d => 0}, {d => -1}, {d => 1}]"); ## ## repeated_nested_enum ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_nested_enum => [ProtobufUnittest::TestAllTypes::NestedEnum::FOO(), ProtobufUnittest::TestAllTypes::NestedEnum::BAR()]}); is($str, "\x{98}\x{03}\x{01}\x{98}\x{03}\x{02}", "repeated_nested_enum:[FOO, BAR]"); ## ## repeated_string_piece ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_string_piece => [""]}); is($str, "\x{b2}\x{03}\x{00}", "repeated_string_piece=[\\x{22}\\x{22}]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_string_piece => ["a"]}); is($str, "\x{b2}\x{03}\x{01}a", "repeated_string_piece=[\\x{22}a\\x{22}]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_string_piece => ["a", "b", "\x{0d}\x{0a}"]}); is($str, "\x{b2}\x{03}\x{01}a\x{b2}\x{03}\x{01}b\x{b2}\x{03}\x{02}\x{0d}\x{0a}", "repeated_string_piece=[\\x{22}a\\x{22}, \\x{22}b\\x{22}, \\x{22}\\x{5c}x{0d}\\x{5c}x{0a}\\x{22}]"); ## ## repeated_cord ## $str = ProtobufUnittest::TestAllTypes->encode({repeated_cord => [""]}); is($str, "\x{ba}\x{03}\x{00}", "repeated_cord=[\\x{22}\\x{22}]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_cord => ["a"]}); is($str, "\x{ba}\x{03}\x{01}a", "repeated_cord=[\\x{22}a\\x{22}]"); $str = ProtobufUnittest::TestAllTypes->encode({repeated_cord => ["a", "b", "\x{0d}\x{0a}"]}); is($str, "\x{ba}\x{03}\x{01}a\x{ba}\x{03}\x{01}b\x{ba}\x{03}\x{02}\x{0d}\x{0a}", "repeated_cord=[\\x{22}a\\x{22}, \\x{22}b\\x{22}, \\x{22}\\x{5c}x{0d}\\x{5c}x{0a}\\x{22}]"); Google-ProtocolBuffers-0.12/t/04-decoder.t000755 000765 000024 00000076412 12773206454 020232 0ustar00wesstaff000000 000000 use Test::More tests => 169; use strict; use warnings; use Google::ProtocolBuffers; use Math::BigInt; BEGIN{ $SIG{__DIE__} = \&Carp::confess; } Google::ProtocolBuffers->parsefile( "google/protobuf/unittest.proto", { include_dir => 't' } ); my $data; ## ## optional_int32 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{08}\x{00}"); is($data->{optional_int32}, 0, "optional_int32=0"); $data = ProtobufUnittest::TestAllTypes->decode("\x{08}\x{01}"); is($data->{optional_int32}, 1, "optional_int32=1"); $data = ProtobufUnittest::TestAllTypes->decode("\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is($data->{optional_int32}, -1, "optional_int32=-1"); $data = ProtobufUnittest::TestAllTypes->decode("\x{08}\x{02}"); is($data->{optional_int32}, 2, "optional_int32=2"); $data = ProtobufUnittest::TestAllTypes->decode("\x{08}\x{80}\x{b7}\x{01}"); is($data->{optional_int32}, 23424, "optional_int32=23424"); $data = ProtobufUnittest::TestAllTypes->decode("\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{07}"); is($data->{optional_int32}, 2147483647, "optional_int32=2147483647"); $data = ProtobufUnittest::TestAllTypes->decode("\x{08}\x{80}\x{80}\x{80}\x{80}\x{f8}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is($data->{optional_int32}, -2147483648, "optional_int32=-2147483648"); ## ## optional_int64 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{10}\x{00}"); is($data->{optional_int64}, 0, "optional_int64=0"); $data = ProtobufUnittest::TestAllTypes->decode("\x{10}\x{01}"); is($data->{optional_int64}, 1, "optional_int64=1"); $data = ProtobufUnittest::TestAllTypes->decode("\x{10}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is($data->{optional_int64}, -1, "optional_int64=-1"); $data = ProtobufUnittest::TestAllTypes->decode("\x{10}\x{fa}\x{8a}\x{cb}\x{cb}\x{e8}\x{06}"); is($data->{optional_int64}, Math::BigInt->new("234234234234"), "optional_int64=Math::BigInt->new(\\x{22}234234234234\\x{22})"); $data = ProtobufUnittest::TestAllTypes->decode("\x{10}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{7f}"); is($data->{optional_int64}, Math::BigInt->new("9223372036854775807"), "optional_int64=Math::BigInt->new(\\x{22}9223372036854775807\\x{22})"); $data = ProtobufUnittest::TestAllTypes->decode("\x{10}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{01}"); is($data->{optional_int64}, Math::BigInt->new("-9223372036854775808"), "optional_int64=Math::BigInt->new(\\x{22}-9223372036854775808\\x{22})"); ## ## optional_uint32 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{18}\x{00}"); is($data->{optional_uint32}, 0, "optional_uint32=0"); $data = ProtobufUnittest::TestAllTypes->decode("\x{18}\x{01}"); is($data->{optional_uint32}, 1, "optional_uint32=1"); $data = ProtobufUnittest::TestAllTypes->decode("\x{18}\x{02}"); is($data->{optional_uint32}, 2, "optional_uint32=2"); $data = ProtobufUnittest::TestAllTypes->decode("\x{18}\x{da}\x{f4}\x{90}\x{01}"); is($data->{optional_uint32}, 2374234, "optional_uint32=2374234"); $data = ProtobufUnittest::TestAllTypes->decode("\x{18}\x{ff}\x{ff}\x{ff}\x{ff}\x{0f}"); is($data->{optional_uint32}, 4294967295, "optional_uint32=4294967295"); ## ## optional_uint64 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{20}\x{00}"); is($data->{optional_uint64}, 0, "optional_uint64=0"); $data = ProtobufUnittest::TestAllTypes->decode("\x{20}\x{01}"); is($data->{optional_uint64}, 1, "optional_uint64=1"); $data = ProtobufUnittest::TestAllTypes->decode("\x{20}\x{02}"); is($data->{optional_uint64}, 2, "optional_uint64=2"); $data = ProtobufUnittest::TestAllTypes->decode("\x{20}\x{fa}\x{8d}\x{e8}\x{c8}\x{ff}C"); is($data->{optional_uint64}, Math::BigInt->new("2336346474234"), "optional_uint64=Math::BigInt->new(\\x{22}2336346474234\\x{22})"); $data = ProtobufUnittest::TestAllTypes->decode("\x{20}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is($data->{optional_uint64}, Math::BigInt->new("18446744073709551615"), "optional_uint64=Math::BigInt->new(\\x{22}18446744073709551615\\x{22})"); ## ## optional_sint32 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{28}\x{00}"); is($data->{optional_sint32}, 0, "optional_sint32=0"); $data = ProtobufUnittest::TestAllTypes->decode("\x{28}\x{02}"); is($data->{optional_sint32}, 1, "optional_sint32=1"); $data = ProtobufUnittest::TestAllTypes->decode("\x{28}\x{01}"); is($data->{optional_sint32}, -1, "optional_sint32=-1"); $data = ProtobufUnittest::TestAllTypes->decode("\x{28}\x{04}"); is($data->{optional_sint32}, 2, "optional_sint32=2"); $data = ProtobufUnittest::TestAllTypes->decode("\x{28}\x{fc}\x{fc}\x{1c}"); is($data->{optional_sint32}, 237374, "optional_sint32=237374"); $data = ProtobufUnittest::TestAllTypes->decode("\x{28}\x{fb}\x{8a}\x{d1}\x{04}"); is($data->{optional_sint32}, -4858558, "optional_sint32=-4858558"); $data = ProtobufUnittest::TestAllTypes->decode("\x{28}\x{fe}\x{ff}\x{ff}\x{ff}\x{0f}"); is($data->{optional_sint32}, 2147483647, "optional_sint32=2147483647"); $data = ProtobufUnittest::TestAllTypes->decode("\x{28}\x{ff}\x{ff}\x{ff}\x{ff}\x{0f}"); is($data->{optional_sint32}, -2147483648, "optional_sint32=-2147483648"); ## ## optional_sint64 ## $data = ProtobufUnittest::TestAllTypes->decode("0\x{00}"); is($data->{optional_sint64}, 0, "optional_sint64=0"); $data = ProtobufUnittest::TestAllTypes->decode("0\x{02}"); is($data->{optional_sint64}, 1, "optional_sint64=1"); $data = ProtobufUnittest::TestAllTypes->decode("0\x{01}"); is($data->{optional_sint64}, -1, "optional_sint64=-1"); $data = ProtobufUnittest::TestAllTypes->decode("0\x{04}"); is($data->{optional_sint64}, 2, "optional_sint64=2"); $data = ProtobufUnittest::TestAllTypes->decode("0\x{f4}\x{95}\x{96}\x{97}\x{d1}\x{0d}"); is($data->{optional_sint64}, Math::BigInt->new("234234234234"), "optional_sint64=Math::BigInt->new(\\x{22}234234234234\\x{22})"); $data = ProtobufUnittest::TestAllTypes->decode("0\x{fe}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is($data->{optional_sint64}, Math::BigInt->new("9223372036854775807"), "optional_sint64=Math::BigInt->new(\\x{22}9223372036854775807\\x{22})"); $data = ProtobufUnittest::TestAllTypes->decode("0\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is($data->{optional_sint64}, Math::BigInt->new("-9223372036854775808"), "optional_sint64=Math::BigInt->new(\\x{22}-9223372036854775808\\x{22})"); ## ## optional_fixed32 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{3d}\x{00}\x{00}\x{00}\x{00}"); is($data->{optional_fixed32}, 0, "optional_fixed32=0"); $data = ProtobufUnittest::TestAllTypes->decode("\x{3d}\x{01}\x{00}\x{00}\x{00}"); is($data->{optional_fixed32}, 1, "optional_fixed32=1"); $data = ProtobufUnittest::TestAllTypes->decode("\x{3d}\x{02}\x{00}\x{00}\x{00}"); is($data->{optional_fixed32}, 2, "optional_fixed32=2"); $data = ProtobufUnittest::TestAllTypes->decode("\x{3d}\x{08}\x{2b}\x{a2}V"); is($data->{optional_fixed32}, 1453468424, "optional_fixed32=1453468424"); $data = ProtobufUnittest::TestAllTypes->decode("\x{3d}\x{ff}\x{ff}\x{ff}\x{7f}"); is($data->{optional_fixed32}, 2147483647, "optional_fixed32=2147483647"); $data = ProtobufUnittest::TestAllTypes->decode("\x{3d}\x{ff}\x{ff}\x{ff}\x{ff}"); is($data->{optional_fixed32}, 4294967295, "optional_fixed32=4294967295"); ## ## optional_fixed64 ## $data = ProtobufUnittest::TestAllTypes->decode("A\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}"); is($data->{optional_fixed64}, 0, "optional_fixed64=0"); $data = ProtobufUnittest::TestAllTypes->decode("A\x{01}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}"); is($data->{optional_fixed64}, 1, "optional_fixed64=1"); $data = ProtobufUnittest::TestAllTypes->decode("A\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}"); is($data->{optional_fixed64}, 2, "optional_fixed64=2"); $data = ProtobufUnittest::TestAllTypes->decode("Az\x{c5}r\x{89}6\x{00}\x{00}\x{00}"); is($data->{optional_fixed64}, Math::BigInt->new("234234234234"), "optional_fixed64=Math::BigInt->new(\\x{22}234234234234\\x{22})"); $data = ProtobufUnittest::TestAllTypes->decode("A\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{7f}"); is($data->{optional_fixed64}, Math::BigInt->new("9223372036854775807"), "optional_fixed64=Math::BigInt->new(\\x{22}9223372036854775807\\x{22})"); $data = ProtobufUnittest::TestAllTypes->decode("A\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}"); is($data->{optional_fixed64}, Math::BigInt->new("18446744073709551615"), "optional_fixed64=Math::BigInt->new(\\x{22}18446744073709551615\\x{22})"); ## ## optional_sfixed32 ## $data = ProtobufUnittest::TestAllTypes->decode("M\x{00}\x{00}\x{00}\x{00}"); is($data->{optional_sfixed32}, 0, "optional_sfixed32=0"); $data = ProtobufUnittest::TestAllTypes->decode("M\x{01}\x{00}\x{00}\x{00}"); is($data->{optional_sfixed32}, 1, "optional_sfixed32=1"); $data = ProtobufUnittest::TestAllTypes->decode("M\x{ff}\x{ff}\x{ff}\x{ff}"); is($data->{optional_sfixed32}, -1, "optional_sfixed32=-1"); $data = ProtobufUnittest::TestAllTypes->decode("M\x{02}\x{00}\x{00}\x{00}"); is($data->{optional_sfixed32}, 2, "optional_sfixed32=2"); $data = ProtobufUnittest::TestAllTypes->decode("MH\x{94}aC"); is($data->{optional_sfixed32}, 1130468424, "optional_sfixed32=1130468424"); $data = ProtobufUnittest::TestAllTypes->decode("M\x{ff}\x{ff}\x{ff}\x{7f}"); is($data->{optional_sfixed32}, 2147483647, "optional_sfixed32=2147483647"); $data = ProtobufUnittest::TestAllTypes->decode("M\x{00}\x{00}\x{00}\x{80}"); is($data->{optional_sfixed32}, -2147483648, "optional_sfixed32=-2147483648"); ## ## optional_sfixed64 ## $data = ProtobufUnittest::TestAllTypes->decode("Q\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}"); is($data->{optional_sfixed64}, 0, "optional_sfixed64=0"); $data = ProtobufUnittest::TestAllTypes->decode("Q\x{01}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}"); is($data->{optional_sfixed64}, 1, "optional_sfixed64=1"); $data = ProtobufUnittest::TestAllTypes->decode("Q\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}"); is($data->{optional_sfixed64}, -1, "optional_sfixed64=-1"); $data = ProtobufUnittest::TestAllTypes->decode("Q\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}"); is($data->{optional_sfixed64}, 2, "optional_sfixed64=2"); $data = ProtobufUnittest::TestAllTypes->decode("Qz\x{c5}r\x{89}6\x{00}\x{00}\x{00}"); is($data->{optional_sfixed64}, Math::BigInt->new("234234234234"), "optional_sfixed64=Math::BigInt->new(\\x{22}234234234234\\x{22})"); $data = ProtobufUnittest::TestAllTypes->decode("Q\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{7f}"); is($data->{optional_sfixed64}, Math::BigInt->new("9223372036854775807"), "optional_sfixed64=Math::BigInt->new(\\x{22}9223372036854775807\\x{22})"); $data = ProtobufUnittest::TestAllTypes->decode("Q\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{80}"); is($data->{optional_sfixed64}, Math::BigInt->new("-9223372036854775808"), "optional_sfixed64=Math::BigInt->new(\\x{22}-9223372036854775808\\x{22})"); ## ## optional_float ## $data = ProtobufUnittest::TestAllTypes->decode("\x{5d}\x{00}\x{00}\x{00}\x{00}"); cmp_ok($data->{optional_float}, '==', 0, "optional_float=0"); $data = ProtobufUnittest::TestAllTypes->decode("\x{5d}\x{00}\x{00}\x{80}\x{3f}"); ok(abs(1-$data->{optional_float}/(1))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("\x{5d}\x{00}\x{00}\x{00}\x{3f}"); ok(abs(1-$data->{optional_float}/(0.5))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("\x{5d}\x{00}\x{00}\x{00}\x{bf}"); ok(abs(1-$data->{optional_float}/(-0.5))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("\x{5d}\x{f9}\x{02}\x{15}P"); ok(abs(1-$data->{optional_float}/(10000000000))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("\x{5d}\x{ec}x\x{ad}\x{e0}"); ok(abs(1-$data->{optional_float}/(-1e+020))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("\x{5d}\x{ff}\x{e6}\x{db}\x{2e}"); ok(abs(1-$data->{optional_float}/(1e-010))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("\x{5d}\x{08}\x{e5}\x{bc}\x{9e}"); ok(abs(1-$data->{optional_float}/(-2e-020))<0.0000001); ## ## optional_double ## $data = ProtobufUnittest::TestAllTypes->decode("a\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}"); cmp_ok($data->{optional_double}, '==', 0, "optional_double=0"); $data = ProtobufUnittest::TestAllTypes->decode("a\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{f0}\x{3f}"); ok(abs(1-$data->{optional_double}/(1))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("a\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{e0}\x{3f}"); ok(abs(1-$data->{optional_double}/(0.5))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("a\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{e0}\x{bf}"); ok(abs(1-$data->{optional_double}/(-0.5))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("a\x{00}\x{00}\x{00}\x{20}_\x{a0}\x{02}B"); ok(abs(1-$data->{optional_double}/(10000000000))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("a\x{40}\x{8c}\x{b5}x\x{1d}\x{af}\x{15}\x{c4}"); ok(abs(1-$data->{optional_double}/(-1e+020))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("a\x{bb}\x{bd}\x{d7}\x{d9}\x{df}\x{7c}\x{db}\x{3d}"); ok(abs(1-$data->{optional_double}/(1e-010))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("a\x{23}B\x{92}\x{0c}\x{a1}\x{9c}\x{d7}\x{bb}"); ok(abs(1-$data->{optional_double}/(-2e-020))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("a\x{9c}Ww\x{27}\x{26}l\x{a1}7"); ok(abs(1-$data->{optional_double}/(1e-040))<0.0000001); $data = ProtobufUnittest::TestAllTypes->decode("a\x{9a}d\x{7e}\x{c5}\x{0e}\x{1b}QJ"); ok(abs(1-$data->{optional_double}/(1e+050))<0.0000001); ## ## optional_bool ## $data = ProtobufUnittest::TestAllTypes->decode("h\x{00}"); is($data->{optional_bool}, 0, "optional_bool=0"); $data = ProtobufUnittest::TestAllTypes->decode("h\x{01}"); is($data->{optional_bool}, 1, "optional_bool=1"); ## ## optional_string ## $data = ProtobufUnittest::TestAllTypes->decode("r\x{00}"); is($data->{optional_string}, "", "optional_string=\\x{22}\\x{22}"); $data = ProtobufUnittest::TestAllTypes->decode("r\x{01}\x{09}"); is($data->{optional_string}, "\x{09}", "optional_string=\\x{22}\\x{5c}x{09}\\x{22}"); $data = ProtobufUnittest::TestAllTypes->decode("r\x{01}\x{0a}"); is($data->{optional_string}, "\x{0a}", "optional_string=\\x{22}\\x{5c}x{0a}\\x{22}"); $data = ProtobufUnittest::TestAllTypes->decode("r\x{01}\x{0d}"); is($data->{optional_string}, "\x{0d}", "optional_string=\\x{22}\\x{5c}x{0d}\\x{22}"); $data = ProtobufUnittest::TestAllTypes->decode("r\x{0c}Hello\x{2c}\x{20}world"); is($data->{optional_string}, "Hello\x{2c}\x{20}world", "optional_string=\\x{22}Hello\\x{5c}x{2c}\\x{5c}x{20}world\\x{22}"); ## ## optional_bytes ## $data = ProtobufUnittest::TestAllTypes->decode("z\x{00}"); is($data->{optional_bytes}, "", "optional_bytes=\\x{22}\\x{22}"); $data = ProtobufUnittest::TestAllTypes->decode("z\x{01}\x{00}"); is($data->{optional_bytes}, "\x{00}", "optional_bytes=\\x{22}\\x{5c}x{00}\\x{22}"); $data = ProtobufUnittest::TestAllTypes->decode("z\x{0c}Hello\x{2c}\x{20}world"); is($data->{optional_bytes}, "Hello\x{2c}\x{20}world", "optional_bytes=\\x{22}Hello\\x{5c}x{2c}\\x{5c}x{20}world\\x{22}"); $data = ProtobufUnittest::TestAllTypes->decode("z\x{03}\x{ff}\x{fe}\x{fd}"); is($data->{optional_bytes}, "\x{ff}\x{fe}\x{fd}", "optional_bytes=\\x{22}\\x{5c}x{ff}\\x{5c}x{fe}\\x{5c}x{fd}\\x{22}"); ## ## OptionalGroup ## $data = ProtobufUnittest::TestAllTypes->decode("\x{83}\x{01}\x{88}\x{01}\x{00}\x{84}\x{01}"); is_deeply($data->{OptionalGroup}, {a => 0}, "OptionalGroup={a => 0}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{83}\x{01}\x{88}\x{01}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}\x{84}\x{01}"); is_deeply($data->{OptionalGroup}, {a => -1}, "OptionalGroup={a => -1}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{83}\x{01}\x{88}\x{01}\x{c7}\x{01}\x{84}\x{01}"); is_deeply($data->{OptionalGroup}, {a => 199}, "OptionalGroup={a => 199}"); ## ## optional_nested_message ## $data = ProtobufUnittest::TestAllTypes->decode("\x{92}\x{01}\x{02}\x{08}\x{00}"); is_deeply($data->{optional_nested_message}, {bb => 0}, "optional_nested_message={bb => 0}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{92}\x{01}\x{02}\x{08}\x{01}"); is_deeply($data->{optional_nested_message}, {bb => 1}, "optional_nested_message={bb => 1}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{92}\x{01}\x{0b}\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is_deeply($data->{optional_nested_message}, {bb => -1}, "optional_nested_message={bb => -1}"); ## ## optional_foreign_message ## $data = ProtobufUnittest::TestAllTypes->decode("\x{9a}\x{01}\x{02}\x{08}\x{00}"); is_deeply($data->{optional_foreign_message}, {c => 0}, "optional_foreign_message={c => 0}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{9a}\x{01}\x{0b}\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is_deeply($data->{optional_foreign_message}, {c => -1}, "optional_foreign_message={c => -1}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{9a}\x{01}\x{02}\x{08}\x{01}"); is_deeply($data->{optional_foreign_message}, {c => 1}, "optional_foreign_message={c => 1}"); ## ## optional_import_message ## $data = ProtobufUnittest::TestAllTypes->decode("\x{a2}\x{01}\x{02}\x{08}\x{00}"); is_deeply($data->{optional_import_message}, {d => 0}, "optional_import_message={d => 0}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{a2}\x{01}\x{0b}\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is_deeply($data->{optional_import_message}, {d => -1}, "optional_import_message={d => -1}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{a2}\x{01}\x{02}\x{08}\x{01}"); is_deeply($data->{optional_import_message}, {d => 1}, "optional_import_message={d => 1}"); ## ## optional_nested_enum ## $data = ProtobufUnittest::TestAllTypes->decode("\x{a8}\x{01}\x{01}"); is($data->{optional_nested_enum}, ProtobufUnittest::TestAllTypes::NestedEnum::FOO(), "optional_nested_enum:FOO"); $data = ProtobufUnittest::TestAllTypes->decode("\x{a8}\x{01}\x{02}"); is($data->{optional_nested_enum}, ProtobufUnittest::TestAllTypes::NestedEnum::BAR(), "optional_nested_enum:BAR"); $data = ProtobufUnittest::TestAllTypes->decode("\x{a8}\x{01}\x{03}"); is($data->{optional_nested_enum}, ProtobufUnittest::TestAllTypes::NestedEnum::BAZ(), "optional_nested_enum:BAZ"); ## ## optional_foreign_enum ## $data = ProtobufUnittest::TestAllTypes->decode("\x{b0}\x{01}\x{04}"); is($data->{optional_foreign_enum}, ProtobufUnittest::ForeignEnum::FOREIGN_FOO(), "optional_foreign_enum:FOREIGN_FOO"); $data = ProtobufUnittest::TestAllTypes->decode("\x{b0}\x{01}\x{05}"); is($data->{optional_foreign_enum}, ProtobufUnittest::ForeignEnum::FOREIGN_BAR(), "optional_foreign_enum:FOREIGN_BAR"); $data = ProtobufUnittest::TestAllTypes->decode("\x{b0}\x{01}\x{06}"); is($data->{optional_foreign_enum}, ProtobufUnittest::ForeignEnum::FOREIGN_BAZ(), "optional_foreign_enum:FOREIGN_BAZ"); ## ## optional_import_enum ## $data = ProtobufUnittest::TestAllTypes->decode("\x{b8}\x{01}\x{07}"); is($data->{optional_import_enum}, ProtobufUnittestImport::ImportEnum::IMPORT_FOO(), "optional_import_enum:IMPORT_FOO"); $data = ProtobufUnittest::TestAllTypes->decode("\x{b8}\x{01}\x{08}"); is($data->{optional_import_enum}, ProtobufUnittestImport::ImportEnum::IMPORT_BAR(), "optional_import_enum:IMPORT_BAR"); $data = ProtobufUnittest::TestAllTypes->decode("\x{b8}\x{01}\x{09}"); is($data->{optional_import_enum}, ProtobufUnittestImport::ImportEnum::IMPORT_BAZ(), "optional_import_enum:IMPORT_BAZ"); ## ## optional_string_piece ## $data = ProtobufUnittest::TestAllTypes->decode("\x{c2}\x{01}\x{00}"); is($data->{optional_string_piece}, "", "optional_string_piece=\\x{22}\\x{22}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{c2}\x{01}\x{0c}Hello\x{2c}\x{20}world"); is($data->{optional_string_piece}, "Hello\x{2c}\x{20}world", "optional_string_piece=\\x{22}Hello\\x{5c}x{2c}\\x{5c}x{20}world\\x{22}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{c2}\x{01}\x{03}\x{0d}\x{09}\x{0a}"); is($data->{optional_string_piece}, "\x{0d}\x{09}\x{0a}", "optional_string_piece=\\x{22}\\x{5c}x{0d}\\x{5c}x{09}\\x{5c}x{0a}\\x{22}"); ## ## optional_cord ## $data = ProtobufUnittest::TestAllTypes->decode("\x{ca}\x{01}\x{00}"); is($data->{optional_cord}, "", "optional_cord=\\x{22}\\x{22}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{ca}\x{01}\x{0c}Hello\x{2c}\x{20}world"); is($data->{optional_cord}, "Hello\x{2c}\x{20}world", "optional_cord=\\x{22}Hello\\x{5c}x{2c}\\x{5c}x{20}world\\x{22}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{ca}\x{01}\x{03}\x{0d}\x{09}\x{0a}"); is($data->{optional_cord}, "\x{0d}\x{09}\x{0a}", "optional_cord=\\x{22}\\x{5c}x{0d}\\x{5c}x{09}\\x{5c}x{0a}\\x{22}"); ## ## repeated_int32 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{f8}\x{01}\x{00}"); is_deeply($data->{repeated_int32}, [0], "repeated_int32:0"); $data = ProtobufUnittest::TestAllTypes->decode("\x{f8}\x{01}\x{00}"); is_deeply($data->{repeated_int32}, [0], "repeated_int32=[0]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{f8}\x{01}\x{00}\x{f8}\x{01}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}\x{f8}\x{01}\x{01}"); is_deeply($data->{repeated_int32}, [0, -1, 1], "repeated_int32=[0, -1, 1]"); ## ## repeated_int64 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{80}\x{02}\x{00}"); is_deeply($data->{repeated_int64}, [0], "repeated_int64=[0]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{80}\x{02}\x{00}\x{80}\x{02}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}\x{80}\x{02}\x{01}"); is_deeply($data->{repeated_int64}, [0, -1, 1], "repeated_int64=[0, -1, 1]"); ## ## repeated_uint32 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{88}\x{02}\x{00}"); is_deeply($data->{repeated_uint32}, [0], "repeated_uint32=[0]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{88}\x{02}\x{00}\x{88}\x{02}\x{02}\x{88}\x{02}\x{01}"); is_deeply($data->{repeated_uint32}, [0, 2, 1], "repeated_uint32=[0, 2, 1]"); ## ## repeated_uint64 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{90}\x{02}\x{00}"); is_deeply($data->{repeated_uint64}, [0], "repeated_uint64=[0]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{90}\x{02}\x{00}\x{90}\x{02}\x{02}\x{90}\x{02}\x{01}"); is_deeply($data->{repeated_uint64}, [0, 2, 1], "repeated_uint64=[0, 2, 1]"); ## ## repeated_sint32 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{98}\x{02}\x{00}"); is_deeply($data->{repeated_sint32}, [0], "repeated_sint32=[0]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{98}\x{02}\x{00}\x{98}\x{02}\x{01}\x{98}\x{02}\x{02}"); is_deeply($data->{repeated_sint32}, [0, -1, 1], "repeated_sint32=[0, -1, 1]"); ## ## repeated_sint64 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{a0}\x{02}\x{00}"); is_deeply($data->{repeated_sint64}, [0], "repeated_sint64=[0]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{a0}\x{02}\x{00}\x{a0}\x{02}\x{01}\x{a0}\x{02}\x{02}"); is_deeply($data->{repeated_sint64}, [0, -1, 1], "repeated_sint64=[0, -1, 1]"); ## ## repeated_fixed32 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{ad}\x{02}\x{00}\x{00}\x{00}\x{00}"); is_deeply($data->{repeated_fixed32}, [0], "repeated_fixed32=[0]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{ad}\x{02}\x{00}\x{00}\x{00}\x{00}\x{ad}\x{02}\x{03}\x{00}\x{00}\x{00}\x{ad}\x{02}\x{01}\x{00}\x{00}\x{00}"); is_deeply($data->{repeated_fixed32}, [0, 3, 1], "repeated_fixed32=[0, 3, 1]"); ## ## repeated_fixed64 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{b1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}"); is_deeply($data->{repeated_fixed64}, [0], "repeated_fixed64=[0]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{b1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{b1}\x{02}\x{03}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{b1}\x{02}\x{01}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}"); is_deeply($data->{repeated_fixed64}, [0, 3, 1], "repeated_fixed64=[0, 3, 1]"); ## ## repeated_sfixed32 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{bd}\x{02}\x{00}\x{00}\x{00}\x{00}"); is_deeply($data->{repeated_sfixed32}, [0], "repeated_sfixed32=[0]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{bd}\x{02}\x{00}\x{00}\x{00}\x{00}\x{bd}\x{02}\x{ff}\x{ff}\x{ff}\x{ff}\x{bd}\x{02}\x{01}\x{00}\x{00}\x{00}"); is_deeply($data->{repeated_sfixed32}, [0, -1, 1], "repeated_sfixed32=[0, -1, 1]"); ## ## repeated_sfixed64 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{c1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}"); is_deeply($data->{repeated_sfixed64}, [0], "repeated_sfixed64=[0]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{c1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{c1}\x{02}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{c1}\x{02}\x{01}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}"); is_deeply($data->{repeated_sfixed64}, [0, -1, 1], "repeated_sfixed64=[0, -1, 1]"); ## ## repeated_float ## $data = ProtobufUnittest::TestAllTypes->decode("\x{cd}\x{02}\x{00}\x{00}\x{00}\x{00}"); is_deeply($data->{repeated_float}, [0], "repeated_float=[0]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{cd}\x{02}\x{00}\x{00}\x{00}\x{00}\x{cd}\x{02}\x{00}\x{00}\x{00}\x{bf}\x{cd}\x{02}\x{f9}\x{02}\x{15}P"); is_deeply($data->{repeated_float}, [0, -0.5, 10000000000], "repeated_float=[0, -0.5, 10000000000]"); ## ## repeated_double ## $data = ProtobufUnittest::TestAllTypes->decode("\x{d1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}"); is_deeply($data->{repeated_double}, [0], "repeated_double=[0]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{d1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{d1}\x{02}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{e0}\x{bf}\x{d1}\x{02}\x{00}\x{00}\x{00}\x{20}_\x{a0}\x{02}B"); is_deeply($data->{repeated_double}, [0, -0.5, 10000000000], "repeated_double=[0, -0.5, 10000000000]"); ## ## repeated_bool ## $data = ProtobufUnittest::TestAllTypes->decode("\x{d8}\x{02}\x{00}"); is_deeply($data->{repeated_bool}, [0], "repeated_bool=[0]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{d8}\x{02}\x{00}\x{d8}\x{02}\x{01}\x{d8}\x{02}\x{01}\x{d8}\x{02}\x{00}"); is_deeply($data->{repeated_bool}, [0, 1, 1, 0], "repeated_bool=[0, 1, 1, 0]"); ## ## repeated_string ## $data = ProtobufUnittest::TestAllTypes->decode("\x{e2}\x{02}\x{00}"); is_deeply($data->{repeated_string}, [""], "repeated_string=[\\x{22}\\x{22}]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{e2}\x{02}\x{05}hello"); is_deeply($data->{repeated_string}, ["hello"], "repeated_string=[\\x{22}hello\\x{22}]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{e2}\x{02}\x{05}hello\x{e2}\x{02}\x{05}world"); is_deeply($data->{repeated_string}, ["hello", "world"], "repeated_string=[\\x{22}hello\\x{22}, \\x{22}world\\x{22}]"); ## ## repeated_bytes ## $data = ProtobufUnittest::TestAllTypes->decode("\x{ea}\x{02}\x{00}"); is_deeply($data->{repeated_bytes}, [""], "repeated_bytes=[\\x{22}\\x{22}]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{ea}\x{02}\x{01}\x{00}"); is_deeply($data->{repeated_bytes}, ["\x{00}"], "repeated_bytes=[\\x{22}\\x{5c}x{00}\\x{22}]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{ea}\x{02}\x{00}\x{ea}\x{02}\x{01}\x{00}\x{ea}\x{02}\x{02}\x{00}\x{00}"); is_deeply($data->{repeated_bytes}, ["", "\x{00}", "\x{00}\x{00}"], "repeated_bytes=[\\x{22}\\x{22}, \\x{22}\\x{5c}x{00}\\x{22}, \\x{22}\\x{5c}x{00}\\x{5c}x{00}\\x{22}]"); ## ## RepeatedGroup ## $data = ProtobufUnittest::TestAllTypes->decode("\x{f3}\x{02}\x{f8}\x{02}\x{00}\x{f4}\x{02}"); is_deeply($data->{RepeatedGroup}, [{a => 0}], "RepeatedGroup=[{a => 0}]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{f3}\x{02}\x{f8}\x{02}\x{00}\x{f4}\x{02}\x{f3}\x{02}\x{f8}\x{02}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}\x{f4}\x{02}"); is_deeply($data->{RepeatedGroup}, [{a => 0}, {a => -1}], "RepeatedGroup=[{a => 0}, {a => -1}]"); ## ## repeated_nested_message ## $data = ProtobufUnittest::TestAllTypes->decode("\x{82}\x{03}\x{02}\x{08}\x{00}"); is_deeply($data->{repeated_nested_message}, [{bb => 0}], "repeated_nested_message=[{bb => 0}]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{82}\x{03}\x{02}\x{08}\x{01}\x{82}\x{03}\x{02}\x{08}\x{02}"); is_deeply($data->{repeated_nested_message}, [{bb => 1}, {bb => 2}], "repeated_nested_message=[{bb => 1}, {bb => 2}]"); ## ## repeated_foreign_message ## $data = ProtobufUnittest::TestAllTypes->decode("\x{8a}\x{03}\x{02}\x{08}\x{00}"); is_deeply($data->{repeated_foreign_message}, [{c => 0}], "repeated_foreign_message=[{c => 0}]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{8a}\x{03}\x{02}\x{08}\x{00}\x{8a}\x{03}\x{0b}\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}\x{8a}\x{03}\x{02}\x{08}\x{01}"); is_deeply($data->{repeated_foreign_message}, [{c => 0}, {c => -1}, {c => 1}], "repeated_foreign_message=[{c => 0}, {c => -1}, {c => 1}]"); ## ## repeated_import_message ## $data = ProtobufUnittest::TestAllTypes->decode("\x{92}\x{03}\x{02}\x{08}\x{00}"); is_deeply($data->{repeated_import_message}, [{d => 0}], "repeated_import_message=[{d => 0}]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{92}\x{03}\x{02}\x{08}\x{00}\x{92}\x{03}\x{0b}\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}\x{92}\x{03}\x{02}\x{08}\x{01}"); is_deeply($data->{repeated_import_message}, [{d => 0}, {d => -1}, {d => 1}], "repeated_import_message=[{d => 0}, {d => -1}, {d => 1}]"); ## ## repeated_nested_enum ## $data = ProtobufUnittest::TestAllTypes->decode("\x{98}\x{03}\x{01}\x{98}\x{03}\x{02}"); is_deeply($data->{repeated_nested_enum}, [ProtobufUnittest::TestAllTypes::NestedEnum::FOO(), ProtobufUnittest::TestAllTypes::NestedEnum::BAR()], "repeated_nested_enum:[FOO, BAR]"); ## ## repeated_string_piece ## $data = ProtobufUnittest::TestAllTypes->decode("\x{b2}\x{03}\x{00}"); is_deeply($data->{repeated_string_piece}, [""], "repeated_string_piece=[\\x{22}\\x{22}]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{b2}\x{03}\x{01}a"); is_deeply($data->{repeated_string_piece}, ["a"], "repeated_string_piece=[\\x{22}a\\x{22}]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{b2}\x{03}\x{01}a\x{b2}\x{03}\x{01}b\x{b2}\x{03}\x{02}\x{0d}\x{0a}"); is_deeply($data->{repeated_string_piece}, ["a", "b", "\x{0d}\x{0a}"], "repeated_string_piece=[\\x{22}a\\x{22}, \\x{22}b\\x{22}, \\x{22}\\x{5c}x{0d}\\x{5c}x{0a}\\x{22}]"); ## ## repeated_cord ## $data = ProtobufUnittest::TestAllTypes->decode("\x{ba}\x{03}\x{00}"); is_deeply($data->{repeated_cord}, [""], "repeated_cord=[\\x{22}\\x{22}]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{ba}\x{03}\x{01}a"); is_deeply($data->{repeated_cord}, ["a"], "repeated_cord=[\\x{22}a\\x{22}]"); $data = ProtobufUnittest::TestAllTypes->decode("\x{ba}\x{03}\x{01}a\x{ba}\x{03}\x{01}b\x{ba}\x{03}\x{02}\x{0d}\x{0a}"); is_deeply($data->{repeated_cord}, ["a", "b", "\x{0d}\x{0a}"], "repeated_cord=[\\x{22}a\\x{22}, \\x{22}b\\x{22}, \\x{22}\\x{5c}x{0d}\\x{5c}x{0a}\\x{22}]"); ## ## repeated packed format ## $data = ProtobufUnittest::TestAllTypes->decode("\x{fa}\x{01}\x{06}\x{03}\x{8e}\x{02}\x{9e}\x{a7}\x{05}\x{b2}\x{03}\x{01}a"); is_deeply($data, { repeated_int32 => [3, 270, 86942], repeated_string_piece=>["a"]}, "repeated_int32:packed_format"); Google-ProtocolBuffers-0.12/t/05-enums.t000755 000765 000024 00000003212 12773206454 017741 0ustar00wesstaff000000 000000 use Test::More tests => 27; use strict; use warnings; use Google::ProtocolBuffers; use Math::BigInt; BEGIN{ $SIG{__DIE__} = \&Carp::confess; } Google::ProtocolBuffers->parsefile( "google/protobuf/unittest.proto", { include_dir => 't' } ); is(ProtobufUnittest::TestAllTypes::NestedEnum::FOO(), 1); is(ProtobufUnittest::TestAllTypes::NestedEnum::BAR(), 2); is(ProtobufUnittest::TestAllTypes::NestedEnum::BAZ(), 3); ProtobufUnittest::TestAllTypes::NestedEnum->import(':constants'); is(FOO(), 1); is(BAR(), 2); is(BAZ(), 3); ProtobufUnittest::ForeignEnum->import(':constants'); is(FOREIGN_FOO(), 4); is(FOREIGN_BAR(), 5); is(FOREIGN_BAZ(), 6); { no warnings 'redefine'; ## doesn't help, since redefine occurs ## in Exporter block of code package ImportHere; ProtobufUnittest::TestEnumWithDupValue->import(':constants'); package main; is(ImportHere::FOO1(), 1); is(ImportHere::BAR1(), 2); is(ImportHere::BAZ(), 3); ## redefined! is(ImportHere::FOO2(), 1); is(ImportHere::BAR2(), 2); } ProtobufUnittest::TestSparseEnum->import(':constants'); is(SPARSE_A(), 123); is(SPARSE_B(), 62374); is(SPARSE_C(), 12589234); is(SPARSE_D(), -15); is(SPARSE_E(), -53452); is(SPARSE_F(), 0); is(SPARSE_G(), 2); ProtobufUnittestImport::ImportEnum->import(':constants'); is(IMPORT_FOO(), 7); is(IMPORT_BAR(), 8); is(IMPORT_BAZ(), 9); Google::ProtocolBuffers->parsefile( "extra/enumalias.proto", { include_dir => 't' } ); is(EnumAlias::Status::UNKNOWN(), 0); is(EnumAlias::Status::STARTED(), 1); is(EnumAlias::Status::RUNNING(), 1); Google-ProtocolBuffers-0.12/t/06-accessors.t000755 000765 000024 00000001656 12773206454 020612 0ustar00wesstaff000000 000000 use Test::More tests => 7; use strict; use warnings; use Google::ProtocolBuffers; use Math::BigInt; BEGIN{ $SIG{__DIE__} = \&Carp::confess; } Google::ProtocolBuffers->parsefile( "google/protobuf/unittest.proto", { include_dir => 't', create_accessors=>1 } ); my $data = ProtobufUnittest::TestAllTypes->new({optional_int32 => 10}); is($data->optional_int32, 10); $data->optional_int32(100); is($data->optional_int32, 100); $data->optional_int32(20); is($data->optional_int32, 20); $data->optional_int32(0); is($data->optional_int32, 0); $data->RepeatedGroup([ ProtobufUnittest::TestAllTypes::RepeatedGroup->new({a => 11 }), ProtobufUnittest::TestAllTypes::RepeatedGroup->new({a => 12 }), ProtobufUnittest::TestAllTypes::RepeatedGroup->new({a => 13 }), ]); is($data->RepeatedGroup->[0]->{a}, 11); is($data->RepeatedGroup->[1]->{a}, 12); is($data->RepeatedGroup->[2]->{a}, 13); Google-ProtocolBuffers-0.12/t/07-extensions.t000755 000765 000024 00000004204 12773206454 021015 0ustar00wesstaff000000 000000 use Test::More tests => 24; use strict; use warnings; use Google::ProtocolBuffers; BEGIN{ $SIG{__DIE__} = \&Carp::confess; } Google::ProtocolBuffers->parse( " package my.test; message R { optional int32 a = 1; extensions 10 to max; } extend R { optional int32 b = 10; } message RFoo { extend R { optional int32 c = 11; } } ", { create_accessors => 1, simple_extensions => 1 } ); my $r = My::Test::R->new(); $r->a(10); is($r->a, 10); is($r->{a}, 10); $r->b(100); is($r->b, 100); is($r->{b}, 100); $r->c(1000); is($r->c, 1000); is($r->{c}, 1000); is($r->encode, "\x{08}\x{0a}PdX\x{e8}\x{07}"); my $rv = eval { Google::ProtocolBuffers->parse( " package my.test; message S { optional int32 a = 1; extensions 10 to max; } extend S { optional int32 a = 10; } ", { simple_extensions => 1 } ); }; ok(!$rv); Google::ProtocolBuffers->parse( " package my.test; message U { optional int32 a = 1; extensions 10 to max; } extend U { optional int32 a = 10; } message UFoo { extend U { optional int32 a = 11; } } ", { create_accessors => 1 } ); my $u = My::Test::U->decode("\x{08}\x{0a}PdX\x{e8}\x{07}"); is($u->{a}, 10); is($u->{'[a]'}, 100); is($u->{'[UFoo.a]'}, 1000); is($u->a, 10); is($u->getExtension('a'), 100); is($u->getExtension('UFoo.a'), 1000); is($u->getExtension('UFoo::a'), 1000); $u->setExtension('a', 20); is($u->getExtension('a'), 20); $u->setExtension('UFoo.a', 200); is($u->getExtension('UFoo::a'), 200); $u->setExtension('UFoo::a', 400); is($u->getExtension('UFoo.a'), 400); ok(!eval{ $u->setExtension('asdf', 400) }); ok(!eval{ $u->getExtension('123') }); Google::ProtocolBuffers->parse( " message TopLevel { optional int32 a = 1; extensions 10 to max; } // b is created as a top-level name extend TopLevel { optional int32 b = 10; } ", { create_accessors => 1, simple_extensions => 1} ); my $t = TopLevel->decode("\x{08}\x{0a}PdX\x{e8}\x{07}"); is($t->{a}, 10); is($t->{'b'}, 100); is($t->a, 10); is($t->b, 100); Google-ProtocolBuffers-0.12/t/08-defaults.t000755 000765 000024 00000015101 12773206454 020424 0ustar00wesstaff000000 000000 use Test::More; use strict; use warnings; use Google::ProtocolBuffers; BEGIN{ $SIG{__DIE__} = \&Carp::confess; } Google::ProtocolBuffers->parsefile( "google/protobuf/unittest.proto", {include_dir => 't', create_accessors => 1 } ); my $data = ProtobufUnittest::TestAllTypes->decode("\x{08}\x{00}"); is($data->{optional_int32}, 0, "optional_int32=0"); ok(defined $data->{optional_int32}); ok(exists $data->{optional_int32}); ##optional int32 default_int32 = 61 [default = 41 ]; ## no value is set, accessor must return the default one ok(!exists $data->{default_int32}); is($data->default_int32, 41); ## after setting a value, the value must be returned instead $data->default_int32(0); ok(exists $data->{default_int32}); is($data->{default_int32}, 0); is($data->default_int32, 0); ## undef will not be serialized, so after decoding, a default value there will be. ## so, it make sense that after setting an undef, we get a default value $data->default_int32(undef); ok(!exists $data->{default_int32}); is($data->default_int32, 41); ## Data object may be get from Class::Accessor's new: $data = ProtobufUnittest::TestAllTypes->new; ok(!exists $data->{default_int32}); is($data->default_int32, 41); $data = ProtobufUnittest::TestAllTypes->new({default_int32=>0}); ok(exists $data->{default_int32}); is($data->default_int32, 0); is($data->{default_int32}, 0); $data = ProtobufUnittest::TestAllTypes->new({default_int32=>undef}); ok(exists $data->{default_int32}); ok(!defined $data->{default_int32}); is($data->default_int32, 41); ## optional int64 default_int64 = 62 [default = 42 ]; is($data->default_int64, 42); ## optional uint32 default_uint32 = 63 [default = 43 ]; is($data->default_uint32, 43); ## optional uint64 default_uint64 = 64 [default = 44 ]; is($data->default_uint64, 44); ## optional sint32 default_sint32 = 65 [default = -45 ]; is($data->default_sint32, -45); ## optional sint64 default_sint64 = 66 [default = 46 ]; is($data->default_sint64, 46); ## optional fixed32 default_fixed32 = 67 [default = 47 ]; is($data->default_fixed32, 47); ## optional fixed64 default_fixed64 = 68 [default = 48 ]; is($data->default_fixed64, 48); ## optional sfixed32 default_sfixed32 = 69 [default = 49 ]; is($data->default_fixed64, 48); ## optional sfixed64 default_sfixed64 = 70 [default = -50 ]; is($data->default_sfixed64, -50); ## optional float default_float = 71 [default = 51.5 ]; is($data->default_float, 51.5); ## optional double default_double = 72 [default = 52e3 ]; cmp_ok($data->default_double, '==', 52000); ## optional bool default_bool = 73 [default = true ]; is($data->default_bool, 1); ## optional string default_string = 74 [default = "hello"]; is($data->default_string, "hello"); ## optional bytes default_bytes = 75 [default = "world"]; is($data->default_bytes, "world"); ## optional NestedEnum default_nested_enum = 81 [default = BAR ]; is($data->default_nested_enum, ProtobufUnittest::TestAllTypes::NestedEnum::BAR()); ## optional ForeignEnum default_foreign_enum = 82 [default = FOREIGN_BAR]; is($data->default_foreign_enum, ProtobufUnittest::ForeignEnum::FOREIGN_BAR()); ## optional protobuf_unittest_import.ImportEnum ## default_import_enum = 83 [default = IMPORT_BAR]; is($data->default_import_enum, ProtobufUnittestImport::ImportEnum::IMPORT_BAR()); ## optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"]; is($data->default_string_piece, "abc"); ## optional string default_cord = 85 [ctype=CORD,default="123"]; is($data->default_cord, "123"); ## ## TestAllExtensions ## $data = ProtobufUnittest::TestAllExtensions->new; is($data->getExtension('default_int32_extension'), 41); is($data->getExtension('default_string_extension'), "hello"); is($data->getExtension('default_nested_enum_extension'), ProtobufUnittest::TestAllTypes::NestedEnum::BAR()); ## ## TestExtremeDefaultValues ## $data = ProtobufUnittest::TestExtremeDefaultValues->new; ## optional bytes escaped_bytes = 1 [default = "\0\001\a\b\f\n\r\t\v\\\'\"\xfe"]; is($data->escaped_bytes, "\0\001\a\b\f\n\r\t\x{0b}\\\'\"\xfe"); ## optional uint32 large_uint32 = 2 [default = 0xFFFFFFFF]; is($data->large_uint32, 0xFFFFFFFF); ## optional uint64 large_uint64 = 3 [default = 0xFFFFFFFFFFFFFFFF]; is($data->large_uint64, Math::BigInt->new("0xFFFFFFFFFFFFFFFF")); ## optional int32 small_int32 = 4 [default = -0x7FFFFFFF]; is($data->small_int32, -0x7FFFFFFF); ## optional int64 small_int64 = 5 [default = -0x7FFFFFFFFFFFFFFF]; is($data->small_int64, Math::BigInt->new("-0x7FFFFFFFFFFFFFFF")); ## optional string utf8_string = 6 [default = "\341\210\264"]; is($data->utf8_string, "\341\210\264"); ## ## Floating point default values: ## Google::ProtocolBuffers->parse(" message TestFP { required float f1 = 1 [ default = 1 ]; required float f2 = 2 [ default = -1 ]; required float f3 = 3 [ default = 1.25 ]; required float f4 = 4 [ default = 1e3 ]; required float f5 = 5 [ default = 1.25e3 ]; required float f6 = 6 [ default = 1.25e-3 ]; required float f7 = 7 [ default = .25 ]; required float f8 = 8 [ default = -.25e-2 ]; required float f9 = 9 [ default = -.25e2 ]; required float f10 = 10 [ default = 52.12e5 ]; required float f11 = 11 [ default = -52.12e-5 ]; } "); $data = TestFP->decode( TestFP->encode({}) ); my $fpLimit = 0.0000001; ok( abs($data->{f1} - 1) <= $fpLimit, "Default floating point value f1" ); ok( abs($data->{f2} + 1) <= $fpLimit, "Default floating point value f2" ); ok( abs($data->{f3} - 1.25) <= $fpLimit, "Default floating point value f3" ); ok( abs($data->{f4} - 1e3) <= $fpLimit, "Default floating point value f4" ); ok( abs($data->{f5} - 1.25e3) <= $fpLimit, "Default floating point value f5" ); ok( abs($data->{f6} - 1.25e-3) <= $fpLimit, "Default floating point value f6" ); ok( abs($data->{f7} - 0.25) <= $fpLimit, "Default floating point value f7" ); ok( abs($data->{f8} + 0.25e-2) <= $fpLimit, "Default floating point value f8" ); ok( abs($data->{f9} + 0.25e2) <= $fpLimit, "Default floating point value f9" ); ok( abs($data->{f10} - 52.12e5) <= $fpLimit, "Default floating point value f10"); ok( abs($data->{f11} + 52.12e-5) <= $fpLimit, "Default floating point value f11"); done_testing();Google-ProtocolBuffers-0.12/t/09-codegen-a.t000755 000765 000024 00000002454 12773206454 020447 0ustar00wesstaff000000 000000 use Test::More tests => 6; use strict; use warnings; use Google::ProtocolBuffers; BEGIN{ $SIG{__DIE__} = \&Carp::confess; } my $r_filename = 't/MyTestR.pm'; unlink($r_filename); ok(-w 't'); ok(! -f $r_filename); Google::ProtocolBuffers->parse( " package my.test; message R { optional int32 a = 1; extensions 10 to max; } extend R { optional int32 b = 10; } message RFoo { extend R { optional int32 c = 11; } } ", { create_accessors => 1, simple_extensions => 1, generate_code => $r_filename, package_name => 'MyPackage::Name::NotUsed', } ); ok(-f $r_filename); my $u_filename = 't/MyTestU.pm'; unlink($u_filename); ok(! -f $u_filename); Google::ProtocolBuffers->parse( " package my.test; message U { optional int32 a = 1; extensions 10 to max; } extend U { optional int32 a = 10; } message UFoo { extend U { optional int32 a = 11; } } ", { create_accessors => 1, generate_code => $u_filename } ); my $t_filename = 't/UnitTest.pm'; unlink($t_filename); ok(! -f $t_filename); Google::ProtocolBuffers->parsefile( "google/protobuf/unittest.proto", { include_dir => 't', generate_code => $t_filename, create_accessors => 1 } ); ok(-f $t_filename); Google-ProtocolBuffers-0.12/t/10-codegen-b.t000755 000765 000024 00000004544 12773206454 020442 0ustar00wesstaff000000 000000 use Test::More tests => 37; use strict; use warnings; use Google::ProtocolBuffers; BEGIN{ $SIG{__DIE__} = \&Carp::confess; } ok(-f 't/MyTestR.pm'); ok(-f 't/MyTestU.pm'); ok(-f 't/UnitTest.pm'); require_ok('t/MyTestR.pm'); require_ok('t/MyTestU.pm'); require_ok('t/UnitTest.pm'); require_ok('t/UnitTest.pm'); ## what about second-time loading? ## ## A couple of test from everywhere: ## ## ## Encoder: ## ## my $str; $str = ProtobufUnittest::TestAllTypes->encode({optional_int32 => 0}); is($str, "\x{08}\x{00}", "optional_int32=0"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int32 => 1}); is($str, "\x{08}\x{01}", "optional_int32=1"); ## ## Decoder ## my $data; $data = ProtobufUnittest::TestAllTypes->decode("\x{9a}\x{01}\x{02}\x{08}\x{00}"); is_deeply($data->{optional_foreign_message}, {c => 0}, "optional_foreign_message={c => 0}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{9a}\x{01}\x{0b}\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is_deeply($data->{optional_foreign_message}, {c => -1}, "optional_foreign_message={c => -1}"); $data = ProtobufUnittest::TestAllTypes->decode("\x{9a}\x{01}\x{02}\x{08}\x{01}"); is_deeply($data->{optional_foreign_message}, {c => 1}, "optional_foreign_message={c => 1}"); ## ## Enums ## ProtobufUnittest::TestSparseEnum->import(':constants'); is(SPARSE_A(), 123); is(SPARSE_B(), 62374); is(SPARSE_C(), 12589234); is(SPARSE_D(), -15); is(SPARSE_E(), -53452); is(SPARSE_F(), 0); is(SPARSE_G(), 2); ## ## Accessors ## $data = ProtobufUnittest::TestAllTypes->new({optional_int32 => 10}); is($data->optional_int32, 10); $data->optional_int32(100); is($data->optional_int32, 100); $data->optional_int32(20); is($data->optional_int32, 20); $data->optional_int32(0); is($data->optional_int32, 0); ## ## Extensions ## my $r = My::Test::R->new(); $r->a(10); is($r->a, 10); is($r->{a}, 10); $r->b(100); is($r->b, 100); is($r->{b}, 100); $r->c(1000); is($r->c, 1000); is($r->{c}, 1000); my $u = My::Test::U->decode("\x{08}\x{0a}PdX\x{e8}\x{07}"); is($u->{a}, 10); is($u->{'[a]'}, 100); is($u->{'[UFoo.a]'}, 1000); is($u->a, 10); is($u->getExtension('a'), 100); is($u->getExtension('UFoo.a'), 1000); is($u->getExtension('UFoo::a'), 1000); $u->setExtension('a', 20); is($u->getExtension('a'), 20); Google-ProtocolBuffers-0.12/t/11-broken.t000755 000765 000024 00000011202 12773206454 020065 0ustar00wesstaff000000 000000 use Test::More tests => 49; use strict; use warnings; use Google::ProtocolBuffers; BEGIN{ $SIG{__DIE__} = \&Carp::confess; } Google::ProtocolBuffers->parsefile( "google/protobuf/unittest.proto", { include_dir => 't' } ); ## ## optional_int32 ## ## one byte off ok(eval { ProtobufUnittest::TestAllTypes->decode("\x{08}\x{00}") }); ok(! eval { ProtobufUnittest::TestAllTypes->decode("\x{08}") }); ok(eval {ProtobufUnittest::TestAllTypes->decode("\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}")}); ok(!eval {ProtobufUnittest::TestAllTypes->decode("\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}")}); ## varint too long ok(!eval {ProtobufUnittest::TestAllTypes->decode("\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}")}); ## ## optional_int64 ## ok(eval{ProtobufUnittest::TestAllTypes->decode("\x{10}\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{10}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{10}\x{ff}")}); ok(eval{ProtobufUnittest::TestAllTypes->decode("\x{10}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{10}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{10}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}")}); ## ## optional_uint32 ## ok(eval{ProtobufUnittest::TestAllTypes->decode("\x{18}\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{18}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{18}\x{ff}")}); ## ## optional_uint64 ## ok(eval{ProtobufUnittest::TestAllTypes->decode("\x{20}\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{20}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{20}\x{ff}")}); ## ## optional_sint32 ## ok(eval{ProtobufUnittest::TestAllTypes->decode("\x{28}\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{28}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{28}\x{ff}")}); ## ## optional_sint64 ## ok(eval{ProtobufUnittest::TestAllTypes->decode("0\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("0")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("0\x{ff}")}); ## ## optional_fixed32 ## ok(eval{ProtobufUnittest::TestAllTypes->decode("\x{3d}\x{00}\x{00}\x{00}\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{3d}\x{00}\x{00}\x{00}")}); ## ## optional_fixed64 ## ok(eval{ProtobufUnittest::TestAllTypes->decode("A\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("A\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}")}); ## ## optional_sfixed32 ## ok(eval{ProtobufUnittest::TestAllTypes->decode("M\x{00}\x{00}\x{00}\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("M\x{00}\x{00}\x{00}")}); ## ## optional_sfixed64 ## ok(eval{ProtobufUnittest::TestAllTypes->decode("Q\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("Q\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}")}); ## ## optional_float ## ok(eval{ProtobufUnittest::TestAllTypes->decode("\x{5d}\x{00}\x{00}\x{00}\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{5d}\x{00}\x{00}\x{00}")}); ## ## optional_double ## ok(eval{ProtobufUnittest::TestAllTypes->decode("a\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("a\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}")}); ## ## optional_bool ## ok(eval{ProtobufUnittest::TestAllTypes->decode("h\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("h")}); ## ## optional_string ## ok(eval{ProtobufUnittest::TestAllTypes->decode("r\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("r")}); ok(eval{ProtobufUnittest::TestAllTypes->decode("r\x{0c}Hello\x{2c}\x{20}world")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("r\x{0c}Hello\x{2c}\x{20}worl")}); ## ## optional_bytes ## ok(eval{ProtobufUnittest::TestAllTypes->decode("z\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("z")}); ok(eval{ProtobufUnittest::TestAllTypes->decode("z\x{01}\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("z\x{01}")}); ## ## OptionalGroup ## ok(eval{ProtobufUnittest::TestAllTypes->decode("\x{83}\x{01}\x{88}\x{01}\x{00}\x{84}\x{01}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{83}\x{01}\x{88}\x{01}\x{00}\x{84}")}); ## ## optional_nested_message ## ok(eval{ProtobufUnittest::TestAllTypes->decode("\x{92}\x{01}\x{02}\x{08}\x{00}")}); ok(!eval{ProtobufUnittest::TestAllTypes->decode("\x{92}\x{01}\x{02}\x{08}")}); Google-ProtocolBuffers-0.12/t/12-unknown.t000755 000765 000024 00000013554 12773206454 020321 0ustar00wesstaff000000 000000 use Test::More tests => 3; use strict; use warnings; use Google::ProtocolBuffers; Google::ProtocolBuffers->parse(<<'PROTO'); message Double { message NestedMessage { optional int32 a1 = 1; optional int32 a2 = 2; } enum NestedEnum { FOO = 1; BAR = 2; BAZ = 3; } // Singular optional int32 a1 = 1; optional int32 a2 = 2; optional int32 a3 = 3; optional int32 a4 = 4; optional int64 b1 = 5; optional int64 b2 = 6; optional uint32 c1 = 7; optional uint32 c2 = 8; optional uint64 d1 = 9; optional uint64 d2 = 10; optional sint32 e1 = 11; optional sint32 e2 = 12; optional sint64 f1 = 13; optional sint64 f2 = 14; optional fixed32 g1 = 15; optional fixed32 g2 = 16; optional fixed64 h1 = 17; optional fixed64 h2 = 18; optional sfixed32 i1 = 19; optional sfixed32 i2 = 20; optional sfixed64 j1 = 21; optional sfixed64 j2 = 22; optional float k1 = 23; optional float k2 = 24; optional double l1 = 25; optional double l2 = 26; optional bool m1 = 27; optional bool m2 = 28; optional string n1 = 29; optional string n2 = 30; optional bytes o1 = 31; optional bytes o2 = 32; optional group Group1 = 33 { optional int32 a1 = 1; optional int32 a2 = 2; } optional group Group2 = 34 { optional int32 a1 = 1; optional int32 a2 = 2; } optional NestedMessage p1 = 35 ; optional NestedMessage p2 = 36 ; optional NestedEnum q1 = 37 ; optional NestedEnum q2 = 38 ; } message Single { message NestedMessage { optional int32 a1 = 1; //optional int32 a2 = 2; } enum NestedEnum { FOO = 1; BAR = 2; BAZ = 3; } // Singular optional int32 a1 = 1; //optional int32 a2 = 2; optional int32 a3 = 3; //optional int32 a4 = 4; optional int64 b1 = 5; //optional int64 b2 = 6; optional uint32 c1 = 7; //optional uint32 c2 = 8; optional uint64 d1 = 9; //optional uint64 d2 = 10; optional sint32 e1 = 11; //optional sint32 e2 = 12; optional sint64 f1 = 13; //optional sint64 f2 = 14; optional fixed32 g1 = 15; //optional fixed32 g2 = 16; optional fixed64 h1 = 17; //optional fixed64 h2 = 18; optional sfixed32 i1 = 19; //optional sfixed32 i2 = 20; optional sfixed64 j1 = 21; //optional sfixed64 j2 = 22; optional float k1 = 23; //optional float k2 = 24; optional double l1 = 25; //optional double l2 = 26; optional bool m1 = 27; //optional bool m2 = 28; optional string n1 = 29; //optional string n2 = 30; optional bytes o1 = 31; //optional bytes o2 = 32; optional group Group1 = 33 { optional int32 a1 = 1; //optional int32 a2 = 2; } //optional group Group2 = 34 { // optional int32 a1 = 1; // optional int32 a2 = 2; //} optional NestedMessage p1 = 35 ; //optional NestedMessage p2 = 36 ; optional NestedEnum q1 = 37 ; //optional NestedEnum q2 = 38 ; } PROTO my $double = { a1 => 1, a2 => 2, a3 => 3, a4 => 4, b1 => 5, b2 => 6, c1 => 7, c2 => 8, d1 => 9, d2 => 10, e1 => 11, e2 => 12, f1 => 13, f2 => 14, g1 => 15, g2 => 16, h1 => 17, h2 => 18, i1 => 19, i2 => 20, j1 => 21, j2 => 22, k1 => 23, k2 => 24, l1 => 25, l2 => 26, m1 => 1, m2 => 1, n1 => "asdf", n2 => "zxcv", o1 => "123", o2 => "098", Group1 => { a1 => 1, a2 => 2, }, Group2 => { a1 => 1, a2 => 2, }, p1 => { a1 => 100, a2 => 200 }, p2 => { a1 => 300, a2 => 400 }, q1 => 2 , q2 => 2 , }; my $single = { a1 => 1, a3 => 3, b1 => 5, c1 => 7, d1 => 9, e1 => 11, f1 => 13, g1 => 15, h1 => 17, i1 => 19, j1 => 21, k1 => 23, l1 => 25, m1 => 1, n1 => "asdf", o1 => "123", Group1 => { a1 => 1, }, p1 => { a1 => 100, }, q1 => 2 , }; my $str = Double->encode($double); is($str, "\x{08}\x{01}\x{10}\x{02}\x{18}\x{03}\x{20}\x{04}\x{28}\x{05}\x{30}\x{06}". "\x{38}\x{07}\x{40}\x{08}\x{48}\x{09}\x{50}\x{0a}\x{58}\x{16}\x{60}\x{18}". "\x{68}\x{1a}\x{70}\x{1c}\x{7d}\x{0f}\x{00}\x{00}\x{00}\x{85}\x{01}\x{10}". "\x{00}\x{00}\x{00}\x{89}\x{01}\x{11}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}". "\x{00}\x{91}\x{01}\x{12}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{9d}". "\x{01}\x{13}\x{00}\x{00}\x{00}\x{a5}\x{01}\x{14}\x{00}\x{00}\x{00}\x{a9}". "\x{01}\x{15}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{b1}\x{01}\x{16}". "\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{bd}\x{01}\x{00}\x{00}\x{b8}". "\x{41}\x{c5}\x{01}\x{00}\x{00}\x{c0}\x{41}\x{c9}\x{01}\x{00}\x{00}\x{00}". "\x{00}\x{00}\x{00}\x{39}\x{40}\x{d1}\x{01}\x{00}\x{00}\x{00}\x{00}\x{00}". "\x{00}\x{3a}\x{40}\x{d8}\x{01}\x{01}\x{e0}\x{01}\x{01}\x{ea}\x{01}\x{04}". "\x{61}\x{73}\x{64}\x{66}\x{f2}\x{01}\x{04}\x{7a}\x{78}\x{63}\x{76}\x{fa}". "\x{01}\x{03}\x{31}\x{32}\x{33}\x{82}\x{02}\x{03}\x{30}\x{39}\x{38}\x{8b}". "\x{02}\x{08}\x{01}\x{10}\x{02}\x{8c}\x{02}\x{93}\x{02}\x{08}\x{01}\x{10}". "\x{02}\x{94}\x{02}\x{9a}\x{02}\x{05}\x{08}\x{64}\x{10}\x{c8}\x{01}\x{a2}". "\x{02}\x{06}\x{08}\x{ac}\x{02}\x{10}\x{90}\x{03}\x{a8}\x{02}\x{02}\x{b0}". "\x{02}\x{02}" ); is_deeply(Double->decode($str), $double); is_deeply(Single->decode($str), $single); Google-ProtocolBuffers-0.12/t/13-native64.t000755 000765 000024 00000015577 12773206454 020272 0ustar00wesstaff000000 000000 use Test::More; use strict; use warnings; use Google::ProtocolBuffers; use Config qw/%Config/; BEGIN { if ($Config{ivsize}<=4) { plan skip_all => "64-bit-only platforms test"; } else { plan tests => 33; } } Google::ProtocolBuffers->parsefile( "google/protobuf/unittest.proto", { include_dir => 't', create_accessors => 1 } ); ## ## Code below should not even compile properly on 32-bit platforms ## no warnings 'portable'; my ($str, $data); ## ## Encoder ## ## ## optional_int32 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_int32 => -1}); is($str, "\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}", "optional_int32=-1"); ## ## optional_int64 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_int64 => 234234234234}); is($str, "\x{10}\x{fa}\x{8a}\x{cb}\x{cb}\x{e8}\x{06}", "optional_int64=234234234234"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int64 => 9223372036854775807}); is($str, "\x{10}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{7f}", "optional_int64=9223372036854775807"); $str = ProtobufUnittest::TestAllTypes->encode({optional_int64 => -9223372036854775808}); is($str, "\x{10}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{01}", "optional_int64=-9223372036854775808"); ## ## optional_uint64 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_uint64 => 2336346474234}); is($str, "\x{20}\x{fa}\x{8d}\x{e8}\x{c8}\x{ff}C", "optional_uint64=2336346474234"); $str = ProtobufUnittest::TestAllTypes->encode({optional_uint64 => 18446744073709551615}); is($str, "\x{20}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}", "optional_uint64=18446744073709551615"); ## ## optional_sint64 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_sint64 => 234234234234 }); is($str, "0\x{f4}\x{95}\x{96}\x{97}\x{d1}\x{0d}", "optional_sint64=234234234234"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint64 => 9223372036854775807 }); is($str, "0\x{fe}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}", "optional_sint64=9223372036854775807"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sint64 => -9223372036854775808 }); is($str, "0\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}", "optional_sint64=-9223372036854775808"); ## ## optional_fixed64 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed64 => 234234234234 }); is($str, "Az\x{c5}r\x{89}6\x{00}\x{00}\x{00}", "optional_fixed64=234234234234"); $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed64 => 9223372036854775807 }); is($str, "A\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{7f}", "optional_fixed64=9223372036854775807"); $str = ProtobufUnittest::TestAllTypes->encode({optional_fixed64 => 18446744073709551615 }); is($str, "A\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}", "optional_fixed64=18446744073709551615"); ## ## optional_sfixed64 ## $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed64 => 234234234234 }); is($str, "Qz\x{c5}r\x{89}6\x{00}\x{00}\x{00}", "optional_sfixed64=234234234234"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed64 => 9223372036854775807 }); is($str, "Q\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{7f}", "optional_sfixed64=9223372036854775807"); $str = ProtobufUnittest::TestAllTypes->encode({optional_sfixed64 => -9223372036854775808 }); is($str, "Q\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{80}", "optional_sfixed64=-9223372036854775808"); ## ## Decoder ## ## ## optional_int32 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{08}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is($data->{optional_int32}, -1, "optional_int32=-1"); ok(!ref $data->{optional_int32}, "It's not a Math::BigInt"); ## ## optional_int64 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{10}\x{fa}\x{8a}\x{cb}\x{cb}\x{e8}\x{06}"); is($data->{optional_int64}, 234234234234, "optional_int64=234234234234"); $data = ProtobufUnittest::TestAllTypes->decode("\x{10}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{7f}"); is($data->{optional_int64}, 9223372036854775807, "optional_int64=9223372036854775807"); $data = ProtobufUnittest::TestAllTypes->decode("\x{10}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{80}\x{01}"); is($data->{optional_int64}, -9223372036854775808, "optional_int64=-9223372036854775808"); ## ## optional_uint64 ## $data = ProtobufUnittest::TestAllTypes->decode("\x{20}\x{fa}\x{8d}\x{e8}\x{c8}\x{ff}C"); is($data->{optional_uint64}, 2336346474234, "optional_uint64=2336346474234"); $data = ProtobufUnittest::TestAllTypes->decode("\x{20}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is($data->{optional_uint64}, 18446744073709551615, "optional_uint64=18446744073709551615"); ## ## optional_sint64 ## $data = ProtobufUnittest::TestAllTypes->decode("0\x{f4}\x{95}\x{96}\x{97}\x{d1}\x{0d}"); is($data->{optional_sint64}, 234234234234, "optional_sint64=234234234234"); $data = ProtobufUnittest::TestAllTypes->decode("0\x{fe}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is($data->{optional_sint64}, 9223372036854775807, "optional_sint64=9223372036854775807"); $data = ProtobufUnittest::TestAllTypes->decode("0\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{01}"); is($data->{optional_sint64}, -9223372036854775808, "optional_sint64=-9223372036854775808"); ## ## optional_fixed64 ## $data = ProtobufUnittest::TestAllTypes->decode("Az\x{c5}r\x{89}6\x{00}\x{00}\x{00}"); is($data->{optional_fixed64}, 234234234234, "optional_fixed64=234234234234"); $data = ProtobufUnittest::TestAllTypes->decode("A\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{7f}"); is($data->{optional_fixed64}, 9223372036854775807, "optional_fixed64=9223372036854775807"); $data = ProtobufUnittest::TestAllTypes->decode("A\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}"); is($data->{optional_fixed64}, 18446744073709551615, "optional_fixed64=18446744073709551615"); ## ## optional_sfixed64 ## $data = ProtobufUnittest::TestAllTypes->decode("Qz\x{c5}r\x{89}6\x{00}\x{00}\x{00}"); is($data->{optional_sfixed64}, 234234234234, "optional_sfixed64=234234234234"); $data = ProtobufUnittest::TestAllTypes->decode("Q\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{ff}\x{7f}"); is($data->{optional_sfixed64}, 9223372036854775807, "optional_sfixed64=9223372036854775807"); $data = ProtobufUnittest::TestAllTypes->decode("Q\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{80}"); is($data->{optional_sfixed64}, -9223372036854775808, "optional_sfixed64=-9223372036854775808"); ## ## Default values ## $data = ProtobufUnittest::TestExtremeDefaultValues->new; ## optional uint64 large_uint64 = 3 [default = 0xFFFFFFFFFFFFFFFF]; is($data->large_uint64, 0xFFFFFFFFFFFFFFFF); ## optional int64 small_int64 = 5 [default = -0x7FFFFFFFFFFFFFFF]; is($data->small_int64, -0x7FFFFFFFFFFFFFFF); Google-ProtocolBuffers-0.12/t/14-oneof.t000755 000765 000024 00000001463 12773206454 017726 0ustar00wesstaff000000 000000 use Test::More tests => 11; use strict; use warnings; use Google::ProtocolBuffers; BEGIN{ $SIG{__DIE__} = \&Carp::confess; } my @classes; @classes = Google::ProtocolBuffers->parse(" package my.test; message TestOneof { oneof test_oneof { string name = 1; int32 serial_number = 2; } }", {create_accessors=>1}); is(scalar @classes, 1); is($classes[0], 'My::Test::TestOneof'); can_ok($classes[0], qw(which_oneof)); my $obj1 = new_ok($classes[0]); ok(!defined($obj1->which_oneof('test_oneof'))); $obj1->name('My Name'); ok($obj1->name() eq 'My Name'); ok($obj1->which_oneof('test_oneof') eq 'name'); ok(!exists($obj1->{'serial_number'})); $obj1->serial_number(12345); ok($obj1->serial_number() == 12345); ok($obj1->which_oneof('test_oneof') eq 'serial_number'); ok(!exists($obj1->{'name'})); Google-ProtocolBuffers-0.12/t/bootstrap.pl000755 000765 000024 00000030566 12773206454 020571 0ustar00wesstaff000000 000000 use strict; use warnings; use Math::BigInt; my @cases = ( optional_int32 => [0, 1, -1, 2, 23424, 0x7fffffff, -0x80000000], optional_int64 => [0, 1, -1, Math::BigInt->new("234234234234"), Math::BigInt->new("0x7fffffffffffffff"), Math::BigInt->new("-0x8000000000000000")], optional_uint32 => [0, 1, 2, 2374234, 0xffffffff], optional_uint64 => [0, 1, 2, Math::BigInt->new("2336346474234"), Math::BigInt->new("0xffffffffffffffff")], optional_sint32 => [0, 1, -1, 2, 237374, -4858558, 0x7fffffff, -0x80000000], optional_sint64 => [0, 1, -1, 2, Math::BigInt->new("234234234234"), Math::BigInt->new("0x7fffffffffffffff"), Math::BigInt->new("-0x8000000000000000")], optional_fixed32 => [0, 1, 2, 1453468424, 0x7fffffff, 0xffffffff], optional_fixed64 => [0, 1, 2, Math::BigInt->new("234234234234"), Math::BigInt->new("0x7fffffffffffffff"), Math::BigInt->new("0xffffffffffffffff")], optional_sfixed32 => [0, 1, -1, 2, 1130468424, 0x7fffffff, -0x80000000], optional_sfixed64 => [0, 1, -1, 2, Math::BigInt->new("234234234234"), Math::BigInt->new("0x7fffffffffffffff"), Math::BigInt->new("-0x8000000000000000")], optional_float => [0, 1, 0.5, -0.5, 1e10, -1e20, 1e-10, -2e-20], optional_double => [0, 1, 0.5, -0.5, 1e10, -1e20, 1e-10, -2e-20, 1e-40, 1e+50], optional_bool => [0, 1], optional_string => ["", "\t", "\n", "\r", "Hello, world",], optional_bytes => ["", "\0", "Hello, world", "\x{ff}\x{fe}\x{fd}"], OptionalGroup => [ {a => 0}, {a => -1}, {a => 199}, ], optional_nested_message => [ {bb => 0}, {bb => 1}, {bb => -1}], optional_foreign_message => [ {c => 0}, {c=> -1}, {c=> 1}], optional_import_message => [ {d=>0}, {d=>-1}, {d=>1}], optional_nested_enum => [ { protoc => 'optional_nested_enum: FOO', encode => '{optional_nested_enum => ProtobufUnittest::TestAllTypes::NestedEnum::FOO()}', decode => 'is($data->{optional_nested_enum}, ProtobufUnittest::TestAllTypes::NestedEnum::FOO(), "optional_nested_enum:FOO")', }, { protoc => 'optional_nested_enum: BAR', encode => '{optional_nested_enum => ProtobufUnittest::TestAllTypes::NestedEnum::BAR()}', decode => 'is($data->{optional_nested_enum}, ProtobufUnittest::TestAllTypes::NestedEnum::BAR(), "optional_nested_enum:BAR")', }, { protoc => 'optional_nested_enum: BAZ', encode => '{optional_nested_enum => ProtobufUnittest::TestAllTypes::NestedEnum::BAZ()}', decode => 'is($data->{optional_nested_enum}, ProtobufUnittest::TestAllTypes::NestedEnum::BAZ(), "optional_nested_enum:BAZ")', }, ], optional_foreign_enum => [ { protoc => 'optional_foreign_enum: FOREIGN_FOO', encode => '{optional_foreign_enum => ProtobufUnittest::ForeignEnum::FOREIGN_FOO()}', decode => 'is($data->{optional_foreign_enum}, ProtobufUnittest::ForeignEnum::FOREIGN_FOO(), "optional_foreign_enum:FOREIGN_FOO")', }, { protoc => 'optional_foreign_enum: FOREIGN_BAR', encode => '{optional_foreign_enum => ProtobufUnittest::ForeignEnum::FOREIGN_BAR()}', decode => 'is($data->{optional_foreign_enum}, ProtobufUnittest::ForeignEnum::FOREIGN_BAR(), "optional_foreign_enum:FOREIGN_BAR")', }, { protoc => 'optional_foreign_enum: FOREIGN_BAZ', encode => '{optional_foreign_enum => ProtobufUnittest::ForeignEnum::FOREIGN_BAZ()}', decode => 'is($data->{optional_foreign_enum}, ProtobufUnittest::ForeignEnum::FOREIGN_BAZ(), "optional_foreign_enum:FOREIGN_BAZ")', }, ], optional_import_enum => [ { protoc => 'optional_import_enum: IMPORT_FOO', encode => '{optional_import_enum => ProtobufUnittestImport::ImportEnum::IMPORT_FOO()}', decode => 'is($data->{optional_import_enum}, ProtobufUnittestImport::ImportEnum::IMPORT_FOO(), "optional_import_enum:IMPORT_FOO")', }, { protoc => 'optional_import_enum: IMPORT_BAR', encode => '{optional_import_enum => ProtobufUnittestImport::ImportEnum::IMPORT_BAR()}', decode => 'is($data->{optional_import_enum}, ProtobufUnittestImport::ImportEnum::IMPORT_BAR(), "optional_import_enum:IMPORT_BAR")', }, { protoc => 'optional_import_enum: IMPORT_BAZ', encode => '{optional_import_enum => ProtobufUnittestImport::ImportEnum::IMPORT_BAZ()}', decode => 'is($data->{optional_import_enum}, ProtobufUnittestImport::ImportEnum::IMPORT_BAZ(), "optional_import_enum:IMPORT_BAZ")', }, ], optional_string_piece => ["", "Hello, world", "\r\t\n"], optional_cord => ["", "Hello, world", "\r\t\n"], repeated_int32 => [ ## test that input field may be a single scalar value ## after deserializing, it will be reference to one-element array { protoc => 'repeated_int32: 0', encode => '{repeated_int32 => 0}', decode => 'is_deeply($data->{repeated_int32}, [0], "repeated_int32:0")', }, [0], [0, -1, 1] ], repeated_int64 => [ [0], [0, -1, 1] ], repeated_uint32 => [ [0], [0, 2, 1] ], repeated_uint64 => [ [0], [0, 2, 1] ], repeated_sint32 => [ [0], [0, -1, 1] ], repeated_sint64 => [ [0], [0, -1, 1] ], repeated_fixed32 => [ [0], [0, 3, 1] ], repeated_fixed64 => [ [0], [0, 3, 1] ], repeated_sfixed32 => [ [0], [0, -1, 1] ], repeated_sfixed64 => [ [0], [0, -1, 1] ], repeated_float => [ [0], [0, -0.5, 1e10] ], repeated_double => [ [0], [0, -0.5, 1e10] ], repeated_bool => [ [0], [0, 1, 1, 0] ], repeated_string => [ [""], ["hello"], ["hello","world" ] ], repeated_bytes => [ [""], ["\0"], ["", "\0", "\0\0" ] ], RepeatedGroup => [ [{a=>0}], [{a=>0}, {a=>-1}] ], repeated_nested_message => [ [{bb=>0}], [{bb=>1}, {bb=>2}] ], repeated_foreign_message => [ [{c=>0}], [{c => 0}, {c=> -1}, {c=> 1}] ], repeated_import_message => [ [{d=>0}], [{d => 0}, {d=> -1}, {d=> 1}] ], repeated_nested_enum => [ { protoc => 'repeated_nested_enum: FOO repeated_nested_enum: BAR', encode => '{repeated_nested_enum => [ProtobufUnittest::TestAllTypes::NestedEnum::FOO(), ProtobufUnittest::TestAllTypes::NestedEnum::BAR()]}', decode => 'is_deeply($data->{repeated_nested_enum}, [ProtobufUnittest::TestAllTypes::NestedEnum::FOO(), ProtobufUnittest::TestAllTypes::NestedEnum::BAR()], "repeated_nested_enum:[FOO, BAR]")', }, ], # repeated ForeignEnum repeated_foreign_enum = 52; # repeated protobuf_unittest_import.ImportEnum repeated_import_enum = 53; repeated_string_piece => [ [""], ["a"], ["a", "b", "\r\n"] ], repeated_cord => [ [""], ["a"], ["a", "b", "\r\n"] ], ); my $number_of_tests = 0; foreach my $i (0..(@cases/2-1)) { $number_of_tests += scalar @{ $cases[$i*2+1] }; } open ENCODER, ">03-encoder.t"; open DECODER, ">04-decoder.t"; print ENCODER <<"."; use Test::More tests => $number_of_tests; use strict; use warnings; use Google::ProtocolBuffers; use Math::BigInt; BEGIN{ \$SIG{__DIE__} = \\&Carp::confess; } Google::ProtocolBuffers->parsefile( "google/protobuf/unittest.proto", { include_dir => 't' } ); my \$str; . print DECODER <<"."; use Test::More tests => $number_of_tests; use strict; use warnings; use Google::ProtocolBuffers; use Math::BigInt; BEGIN{ \$SIG{__DIE__} = \\&Carp::confess; } Google::ProtocolBuffers->parsefile( "google/protobuf/unittest.proto", { include_dir => 't' } ); my \$data; . while (my ($k, $ar) = splice(@cases, 0, 2) ) { print ENCODER "##\n## $k\n##\n"; print DECODER "##\n## $k\n##\n"; foreach my $v (@$ar) { ## ## Write a human-readable message into input file for Google's protoc ## open FILE, ">1"; if (ref($v) && ref($v) eq 'HASH' && $v->{protoc}) { print FILE $v->{protoc}; } elsif (ref($v) && ref($v) eq 'ARRAY') { foreach (@$v) { print FILE "$k: ", get_text_message_value($k, $_), " "; } } else { print FILE "$k: ", get_text_message_value($k, $v); } close FILE; ## ## Run the compiler to encode message ## system("..\\..\\protoc.exe google/protobuf/unittest.proto --encode protobuf_unittest.TestAllTypes <1 >2") ==0 or die; ## ## Read the serialized data ## open FILE, 2; binmode FILE; local $/; my $data = ; close FILE; $data =~ s/(\W)/ '\\x{' . sprintf("%02x", ord($1)) . '}' /ge; ## ## Write scripts for encoder and decoder tests ## if (ref($v) && ref($v) eq 'HASH' && $v->{protoc}) { my $test_name; if ($v->{name}) { $test_name=$v->{name}; } elsif ($v->{decode} =~ /"([^"]+)"\)$/) { $test_name = $1; } else { $test_name = ''; } print ENCODER qq[\$str = ProtobufUnittest::TestAllTypes->encode($v->{encode});\n]; print ENCODER qq[is(\$str, "$data", "$test_name");\n\n]; print DECODER qq[\$data = ProtobufUnittest::TestAllTypes->decode("$data");\n]; print DECODER qq[$v->{decode};\n\n]; } else { my ($perl_literal, $need_deep_cmp) = get_perl_literal($v); my $test_name = qq[$k=$perl_literal]; $test_name =~ s/([\x00-\x1f'"\\$@%\x80-\xff])/ '\\\\x{' . sprintf("%02x", ord($1)) . '}' /ge; print ENCODER qq[\$str = ProtobufUnittest::TestAllTypes->encode({$k => $perl_literal});\n]; print ENCODER qq[is(\$str, "$data", "$test_name");\n\n]; print DECODER qq[\$data = ProtobufUnittest::TestAllTypes->decode("$data");\n]; if ($need_deep_cmp) { print DECODER qq[is_deeply(\$data->{$k}, $perl_literal, "$test_name");\n\n]; } elsif ($k =~ /float|double/) { if ($perl_literal eq '0') { print DECODER qq[cmp_ok(\$data->{$k}, '==', 0, "$test_name");\n\n]; } else { print DECODER qq[ok(abs(1-\$data->{$k}/($perl_literal))<0.0000001);\n\n]; } } else { print DECODER qq[is(\$data->{$k}, $perl_literal, "$test_name");\n\n]; } } } } sub get_text_message_value { my ($k, $v) = @_; if (ref($v) && ref($v) eq 'HASH') { return "{" . join(" ", map {"$_:" . get_text_message_value($k, $v->{$_}) } keys %$v) . "}"; } elsif ($k =~ /bool/) { return ($v) ? 'true' : 'false'; } elsif ($v =~ /^[\d\.e+-]+$/i) { return $v; } else { my $str = $v; $str =~ s/(\W)/ '\\x' . sprintf("%02x", ord($1)) /ge; return "'$str'"; } } sub get_perl_literal { my $v = shift; if (ref($v) && ref($v) eq "ARRAY") { return ("[" . join(", ", map {(get_perl_literal($_))[0]} @$v ) . "]", 1); } elsif (ref($v) && ref($v) eq "HASH") { return ("{" . join(", ", map { "$_ => " . (get_perl_literal($v->{$_}))[0]} keys %$v) . "}", 1); } elsif (ref($v)) { return qq[Math::BigInt->new("$v")]; } elsif ($v =~ /^[\d\.e+-]+$/i) { return $v; } else { my $str = $v; $str =~ s/(\W)/ '\\x{' . sprintf("%02x", ord($1)) . '}' /ge; return qq["$str"]; } } __END__ Google-ProtocolBuffers-0.12/t/extra/000755 000765 000024 00000000000 12773222075 017322 5ustar00wesstaff000000 000000 Google-ProtocolBuffers-0.12/t/google/000755 000765 000024 00000000000 12773222075 017453 5ustar00wesstaff000000 000000 Google-ProtocolBuffers-0.12/t/google/protobuf/000755 000765 000024 00000000000 12773222075 021313 5ustar00wesstaff000000 000000 Google-ProtocolBuffers-0.12/t/google/protobuf/unittest.proto000755 000765 000024 00000040503 12773206454 024267 0ustar00wesstaff000000 000000 // Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. // http://code.google.com/p/protobuf/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Author: kenton@google.com (Kenton Varda) // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. // // A proto file we will use for unit testing. import "google/protobuf/unittest_import.proto"; // We don't put this in a package within proto2 because we need to make sure // that the generated code doesn't depend on being in the proto2 namespace. // In test_util.h we do "using namespace unittest = protobuf_unittest". package protobuf_unittest; // Protos optimized for SPEED use a strict superset of the generated code // of equivalent ones optimized for CODE_SIZE, so we should optimize all our // tests for speed unless explicitly testing code size optimization. option optimize_for = SPEED; option java_outer_classname = "UnittestProto"; // This proto includes every type of field in both singular and repeated // forms. message TestAllTypes { message NestedMessage { // The field name "b" fails to compile in proto1 because it conflicts with // a local variable named "b" in one of the generated methods. Doh. // This file needs to compile in proto1 to test backwards-compatibility. optional int32 bb = 1; } enum NestedEnum { FOO = 1; BAR = 2; BAZ = 3; } // Singular optional int32 optional_int32 = 1; optional int64 optional_int64 = 2; optional uint32 optional_uint32 = 3; optional uint64 optional_uint64 = 4; optional sint32 optional_sint32 = 5; optional sint64 optional_sint64 = 6; optional fixed32 optional_fixed32 = 7; optional fixed64 optional_fixed64 = 8; optional sfixed32 optional_sfixed32 = 9; optional sfixed64 optional_sfixed64 = 10; optional float optional_float = 11; optional double optional_double = 12; optional bool optional_bool = 13; optional string optional_string = 14; optional bytes optional_bytes = 15; optional group OptionalGroup = 16 { optional int32 a = 17; } optional NestedMessage optional_nested_message = 18; optional ForeignMessage optional_foreign_message = 19; optional protobuf_unittest_import.ImportMessage optional_import_message = 20; optional NestedEnum optional_nested_enum = 21; optional ForeignEnum optional_foreign_enum = 22; optional protobuf_unittest_import.ImportEnum optional_import_enum = 23; optional string optional_string_piece = 24 [ctype=STRING_PIECE]; optional string optional_cord = 25 [ctype=CORD]; // Repeated repeated int32 repeated_int32 = 31; repeated int64 repeated_int64 = 32; repeated uint32 repeated_uint32 = 33; repeated uint64 repeated_uint64 = 34; repeated sint32 repeated_sint32 = 35; repeated sint64 repeated_sint64 = 36; repeated fixed32 repeated_fixed32 = 37; repeated fixed64 repeated_fixed64 = 38; repeated sfixed32 repeated_sfixed32 = 39; repeated sfixed64 repeated_sfixed64 = 40; repeated float repeated_float = 41; repeated double repeated_double = 42; repeated bool repeated_bool = 43; repeated string repeated_string = 44; repeated bytes repeated_bytes = 45; repeated group RepeatedGroup = 46 { optional int32 a = 47; } repeated NestedMessage repeated_nested_message = 48; repeated ForeignMessage repeated_foreign_message = 49; repeated protobuf_unittest_import.ImportMessage repeated_import_message = 50; repeated NestedEnum repeated_nested_enum = 51; repeated ForeignEnum repeated_foreign_enum = 52; repeated protobuf_unittest_import.ImportEnum repeated_import_enum = 53; repeated string repeated_string_piece = 54 [ctype=STRING_PIECE]; repeated string repeated_cord = 55 [ctype=CORD]; // Singular with defaults optional int32 default_int32 = 61 [default = 41 ]; optional int64 default_int64 = 62 [default = 42 ]; optional uint32 default_uint32 = 63 [default = 43 ]; optional uint64 default_uint64 = 64 [default = 44 ]; optional sint32 default_sint32 = 65 [default = -45 ]; optional sint64 default_sint64 = 66 [default = 46 ]; optional fixed32 default_fixed32 = 67 [default = 47 ]; optional fixed64 default_fixed64 = 68 [default = 48 ]; optional sfixed32 default_sfixed32 = 69 [default = 49 ]; optional sfixed64 default_sfixed64 = 70 [default = -50 ]; optional float default_float = 71 [default = 51.5 ]; optional double default_double = 72 [default = 52e3 ]; optional bool default_bool = 73 [default = true ]; optional string default_string = 74 [default = "hello"]; optional bytes default_bytes = 75 [default = "world"]; optional NestedEnum default_nested_enum = 81 [default = BAR ]; optional ForeignEnum default_foreign_enum = 82 [default = FOREIGN_BAR]; optional protobuf_unittest_import.ImportEnum default_import_enum = 83 [default = IMPORT_BAR]; optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"]; optional string default_cord = 85 [ctype=CORD,default="123"]; } // Define these after TestAllTypes to make sure the compiler can handle // that. message ForeignMessage { optional int32 c = 1; } enum ForeignEnum { FOREIGN_FOO = 4; FOREIGN_BAR = 5; FOREIGN_BAZ = 6; } message TestAllExtensions { extensions 1 to max; } extend TestAllExtensions { // Singular optional int32 optional_int32_extension = 1; optional int64 optional_int64_extension = 2; optional uint32 optional_uint32_extension = 3; optional uint64 optional_uint64_extension = 4; optional sint32 optional_sint32_extension = 5; optional sint64 optional_sint64_extension = 6; optional fixed32 optional_fixed32_extension = 7; optional fixed64 optional_fixed64_extension = 8; optional sfixed32 optional_sfixed32_extension = 9; optional sfixed64 optional_sfixed64_extension = 10; optional float optional_float_extension = 11; optional double optional_double_extension = 12; optional bool optional_bool_extension = 13; optional string optional_string_extension = 14; optional bytes optional_bytes_extension = 15; optional group OptionalGroup_extension = 16 { optional int32 a = 17; } optional TestAllTypes.NestedMessage optional_nested_message_extension = 18; optional ForeignMessage optional_foreign_message_extension = 19; optional protobuf_unittest_import.ImportMessage optional_import_message_extension = 20; optional TestAllTypes.NestedEnum optional_nested_enum_extension = 21; optional ForeignEnum optional_foreign_enum_extension = 22; optional protobuf_unittest_import.ImportEnum optional_import_enum_extension = 23; optional string optional_string_piece_extension = 24 [ctype=STRING_PIECE]; optional string optional_cord_extension = 25 [ctype=CORD]; // Repeated repeated int32 repeated_int32_extension = 31; repeated int64 repeated_int64_extension = 32; repeated uint32 repeated_uint32_extension = 33; repeated uint64 repeated_uint64_extension = 34; repeated sint32 repeated_sint32_extension = 35; repeated sint64 repeated_sint64_extension = 36; repeated fixed32 repeated_fixed32_extension = 37; repeated fixed64 repeated_fixed64_extension = 38; repeated sfixed32 repeated_sfixed32_extension = 39; repeated sfixed64 repeated_sfixed64_extension = 40; repeated float repeated_float_extension = 41; repeated double repeated_double_extension = 42; repeated bool repeated_bool_extension = 43; repeated string repeated_string_extension = 44; repeated bytes repeated_bytes_extension = 45; repeated group RepeatedGroup_extension = 46 { optional int32 a = 47; } repeated TestAllTypes.NestedMessage repeated_nested_message_extension = 48; repeated ForeignMessage repeated_foreign_message_extension = 49; repeated protobuf_unittest_import.ImportMessage repeated_import_message_extension = 50; repeated TestAllTypes.NestedEnum repeated_nested_enum_extension = 51; repeated ForeignEnum repeated_foreign_enum_extension = 52; repeated protobuf_unittest_import.ImportEnum repeated_import_enum_extension = 53; repeated string repeated_string_piece_extension = 54 [ctype=STRING_PIECE]; repeated string repeated_cord_extension = 55 [ctype=CORD]; // Singular with defaults optional int32 default_int32_extension = 61 [default = 41 ]; optional int64 default_int64_extension = 62 [default = 42 ]; optional uint32 default_uint32_extension = 63 [default = 43 ]; optional uint64 default_uint64_extension = 64 [default = 44 ]; optional sint32 default_sint32_extension = 65 [default = -45 ]; optional sint64 default_sint64_extension = 66 [default = 46 ]; optional fixed32 default_fixed32_extension = 67 [default = 47 ]; optional fixed64 default_fixed64_extension = 68 [default = 48 ]; optional sfixed32 default_sfixed32_extension = 69 [default = 49 ]; optional sfixed64 default_sfixed64_extension = 70 [default = -50 ]; optional float default_float_extension = 71 [default = 51.5 ]; optional double default_double_extension = 72 [default = 52e3 ]; optional bool default_bool_extension = 73 [default = true ]; optional string default_string_extension = 74 [default = "hello"]; optional bytes default_bytes_extension = 75 [default = "world"]; optional TestAllTypes.NestedEnum default_nested_enum_extension = 81 [default = BAR]; optional ForeignEnum default_foreign_enum_extension = 82 [default = FOREIGN_BAR]; optional protobuf_unittest_import.ImportEnum default_import_enum_extension = 83 [default = IMPORT_BAR]; optional string default_string_piece_extension = 84 [ctype=STRING_PIECE, default="abc"]; optional string default_cord_extension = 85 [ctype=CORD, default="123"]; } // We have separate messages for testing required fields because it's // annoying to have to fill in required fields in TestProto in order to // do anything with it. Note that we don't need to test every type of // required filed because the code output is basically identical to // optional fields for all types. message TestRequired { required int32 a = 1; optional int32 dummy2 = 2; required int32 b = 3; extend TestAllExtensions { optional TestRequired single = 1000; repeated TestRequired multi = 1001; } // Pad the field count to 32 so that we can test that IsInitialized() // properly checks multiple elements of has_bits_. optional int32 dummy4 = 4; optional int32 dummy5 = 5; optional int32 dummy6 = 6; optional int32 dummy7 = 7; optional int32 dummy8 = 8; optional int32 dummy9 = 9; optional int32 dummy10 = 10; optional int32 dummy11 = 11; optional int32 dummy12 = 12; optional int32 dummy13 = 13; optional int32 dummy14 = 14; optional int32 dummy15 = 15; optional int32 dummy16 = 16; optional int32 dummy17 = 17; optional int32 dummy18 = 18; optional int32 dummy19 = 19; optional int32 dummy20 = 20; optional int32 dummy21 = 21; optional int32 dummy22 = 22; optional int32 dummy23 = 23; optional int32 dummy24 = 24; optional int32 dummy25 = 25; optional int32 dummy26 = 26; optional int32 dummy27 = 27; optional int32 dummy28 = 28; optional int32 dummy29 = 29; optional int32 dummy30 = 30; optional int32 dummy31 = 31; optional int32 dummy32 = 32; required int32 c = 33; } message TestRequiredForeign { optional TestRequired optional_message = 1; repeated TestRequired repeated_message = 2; optional int32 dummy = 3; } // Test that we can use NestedMessage from outside TestAllTypes. message TestForeignNested { optional TestAllTypes.NestedMessage foreign_nested = 1; } // TestEmptyMessage is used to test unknown field support. message TestEmptyMessage { } // Like above, but declare all field numbers as potential extensions. No // actual extensions should ever be defined for this type. message TestEmptyMessageWithExtensions { extensions 1 to max; } // Test that really large tag numbers don't break anything. message TestReallyLargeTagNumber { // The largest possible tag number is 2^28 - 1, since the wire format uses // three bits to communicate wire type. optional int32 a = 1; optional int32 bb = 268435455; } message TestRecursiveMessage { optional TestRecursiveMessage a = 1; optional int32 i = 2; } // Test that mutual recursion works. message TestMutualRecursionA { optional TestMutualRecursionB bb = 1; } message TestMutualRecursionB { optional TestMutualRecursionA a = 1; optional int32 optional_int32 = 2; } // Test that groups have disjoint field numbers from their siblings and // parents. This is NOT possible in proto1; only proto2. When outputting // proto1, the dup fields should be dropped. message TestDupFieldNumber { optional int32 a = 1; optional group Foo = 2 { optional int32 a = 1; } optional group Bar = 3 { optional int32 a = 1; } } // Needed for a Python test. message TestNestedMessageHasBits { message NestedMessage { repeated int32 nestedmessage_repeated_int32 = 1; repeated ForeignMessage nestedmessage_repeated_foreignmessage = 2; } optional NestedMessage optional_nested_message = 1; } // Test an enum that has multiple values with the same number. enum TestEnumWithDupValue { FOO1 = 1; BAR1 = 2; BAZ = 3; FOO2 = 1; BAR2 = 2; } // Test an enum with large, unordered values. enum TestSparseEnum { SPARSE_A = 123; SPARSE_B = 62374; SPARSE_C = 12589234; SPARSE_D = -15; SPARSE_E = -53452; SPARSE_F = 0; SPARSE_G = 2; } // Test message with CamelCase field names. This violates Protocol Buffer // standard style. message TestCamelCaseFieldNames { optional int32 PrimitiveField = 1; optional string StringField = 2; optional ForeignEnum EnumField = 3; optional ForeignMessage MessageField = 4; optional string StringPieceField = 5 [ctype=STRING_PIECE]; optional string CordField = 6 [ctype=CORD]; repeated int32 RepeatedPrimitiveField = 7; repeated string RepeatedStringField = 8; repeated ForeignEnum RepeatedEnumField = 9; repeated ForeignMessage RepeatedMessageField = 10; repeated string RepeatedStringPieceField = 11 [ctype=STRING_PIECE]; repeated string RepeatedCordField = 12 [ctype=CORD]; } // We list fields out of order, to ensure that we're using field number and not // field index to determine serialization order. message TestFieldOrderings { optional string my_string = 11; extensions 2 to 10; optional int64 my_int = 1; extensions 12 to 100; optional float my_float = 101; } extend TestFieldOrderings { optional string my_extension_string = 50; optional int32 my_extension_int = 5; } message TestExtremeDefaultValues { optional bytes escaped_bytes = 1 [default = "\0\001\a\b\f\n\r\t\v\\\'\"\xfe"]; optional uint32 large_uint32 = 2 [default = 0xFFFFFFFF]; optional uint64 large_uint64 = 3 [default = 0xFFFFFFFFFFFFFFFF]; optional int32 small_int32 = 4 [default = -0x7FFFFFFF]; optional int64 small_int64 = 5 [default = -0x7FFFFFFFFFFFFFFF]; // The default value here is UTF-8 for "\u1234". (We could also just type // the UTF-8 text directly into this text file rather than escape it, but // lots of people use editors that would be confused by this.) optional string utf8_string = 6 [default = "\341\210\264"]; } // Test that RPC services work. message FooRequest {} message FooResponse {} service TestService { rpc Foo(FooRequest) returns (FooResponse); rpc Bar(BarRequest) returns (BarResponse); } message BarRequest {} message BarResponse {} Google-ProtocolBuffers-0.12/t/google/protobuf/unittest_import.proto000755 000765 000024 00000002741 12773206454 025663 0ustar00wesstaff000000 000000 // Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. // http://code.google.com/p/protobuf/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Author: kenton@google.com (Kenton Varda) // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. // // A proto file which is imported by unittest.proto to test importing. // We don't put this in a package within proto2 because we need to make sure // that the generated code doesn't depend on being in the proto2 namespace. // In test_util.h we do // "using namespace unittest_import = protobuf_unittest_import". package protobuf_unittest_import; option optimize_for = SPEED; // Excercise the java_package option. option java_package = "com.google.protobuf.test"; // Do not set a java_outer_classname here to verify that Proto2 works without // one. message ImportMessage { optional int32 d = 1; } enum ImportEnum { IMPORT_FOO = 7; IMPORT_BAR = 8; IMPORT_BAZ = 9; } Google-ProtocolBuffers-0.12/t/extra/enumalias.proto000644 000765 000024 00000000257 12773206454 022374 0ustar00wesstaff000000 000000 message EnumAlias { enum Status { option allow_alias = true; UNKNOWN = 0; STARTED = 1; RUNNING = 1; } required Status status = 1 [default = UNKNOWN]; }Google-ProtocolBuffers-0.12/lib/Google/000755 000765 000024 00000000000 12773222075 017716 5ustar00wesstaff000000 000000 Google-ProtocolBuffers-0.12/lib/Google/ProtocolBuffers/000755 000765 000024 00000000000 12773222075 023034 5ustar00wesstaff000000 000000 Google-ProtocolBuffers-0.12/lib/Google/ProtocolBuffers.pm000755 000765 000024 00000106663 12773206454 023414 0ustar00wesstaff000000 000000 package Google::ProtocolBuffers; use 5.008008; use warnings; use strict; use Google::ProtocolBuffers::Codec; use Google::ProtocolBuffers::Constants qw/:complex_types :labels/; use Class::Accessor; use Math::BigInt; use Carp; use Data::Dumper; our $VERSION = "0.12"; sub parsefile { my $self = shift; my $proto_filename = shift; my $opts = shift || {}; return $self->_parse({file=>$proto_filename}, $opts); } sub parse { my $self = shift; my $proto_text = shift; my $opts = shift || {}; return $self->_parse({text=>$proto_text}, $opts); } ## Positional access is slightly faster than named one. ## Currently, it's in the same order as text in proto file ## "optional" (LABEL) int32 (type) foo (name) = 1 (number) [default=...] use constant { F_LABEL => 0, F_TYPE => 1, F_NAME => 2, F_NUMBER => 3, F_DEFAULT => 4, }; sub _parse { my $self = shift; my $source = shift; my $opts = shift; require 'Google/ProtocolBuffers/Compiler.pm'; my $types = Google::ProtocolBuffers::Compiler->parse($source, $opts); ## ## 1. Create enums - they will be used as default values for fields ## my @created_enums; while (my ($type_name, $desc) = each %$types) { next unless $desc->{kind} eq 'enum'; my $class_name = $self->_get_class_name_for($type_name, $opts); $self->create_enum($class_name, $desc->{fields}); push @created_enums, $class_name; } ## ## 2. Create groups and messages, ## Fill default values of fields and convert their ## types (my_package.message_a) into Perl classes names (MyPackage::MessageA) ## my @created_messages; while (my ($type_name, $desc) = each %$types) { my $kind = $desc->{kind}; my @fields; my %oneofs; if ($kind =~ /^(enum|oneof)$/) { next; } elsif ($kind eq 'group') { push @fields, @{$desc->{fields}}; } elsif ($kind eq 'message') { push @fields, @{$desc->{fields}}; ## ## Get names for extensions fields. ## Original (full quilified) name is like 'package.MessageA.field'. ## If 'simple_extensions' is true, it will be cut to the last element: 'field'. ## Otherwise, it will be enclosed in brackets and all part common to message type ## will be removed, e.g. for message 'package.MessageB' it will be '[MessageA.field]' ## If message is 'other_package.MessageB', it will be '[package.MessageA.field]' ## foreach my $e (@{$desc->{extensions}}) { my $field_name = $e->[F_NAME]; my $new_name; if ($opts->{simple_extensions}) { $new_name = ($field_name =~ /\.(\w+)$/) ? $1 : $field_name; } else { ## remove common identifiers from start of f.q.i. my @type_idents = split qr/\./, $type_name; my @field_idents = split qr/\./, $field_name; while (@type_idents && @field_idents) { last if $type_idents[0] ne $field_idents[0]; shift @type_idents; shift @field_idents; } die "Can't create name for extension field '$field_name' in '$type_name'" unless @field_idents; $new_name = '[' . join('.', @field_idents) . ']'; } $e->[F_NAME] = $new_name; push @fields, $e; } ## ## Get names for oneof fields. ## foreach my $oneof_name (@{$desc->{oneofs}}) { my $oneof = $types->{$oneof_name}; my @oneof_fields = map { $_->[F_NAME] } @{$oneof->{fields}}; my $new_name = ($oneof_name =~ /\.(\w+)$/) ? $1 : $oneof_name; $oneofs{$new_name} = \@oneof_fields; push @fields, @{$oneof->{fields}}; } } else { die; } ## ## Replace proto type names by Perl classes names ## foreach my $f (@fields) { my $type = $f->[F_TYPE]; if ($type !~ /^\d+$/) { ## not a primitive type $f->[F_TYPE] = $self->_get_class_name_for($type, $opts); } } ## ## Default values: replace references to enum idents by their values ## foreach my $f (@fields) { my $default_value = $f->[F_DEFAULT]; if ($default_value && ref $default_value) { ## this default value is a literal die "Unknown default value " . Data::Dumper::Dumper($default_value) unless ref($default_value) eq 'HASH'; $f->[F_DEFAULT] = $default_value->{value}; } elsif ($default_value) { ## this default is an enum value my ($enum_name, $enum_field_name) = ($default_value =~ /(.*)\.(\w+)$/); my $class_name = $self->_get_class_name_for($enum_name, $opts); no strict 'refs'; $f->[F_DEFAULT] = &{"${class_name}::$enum_field_name"}; use strict; } } ## ## Create Perl classes ## my $class_name = $self->_get_class_name_for($type_name, $opts); if ($kind eq 'message') { $self->create_message($class_name, \@fields, \%oneofs, $opts); } elsif ($kind eq 'group') { $self->create_group($class_name, \@fields, $opts); } push @created_messages, $class_name; } my @created_classes = sort @created_enums; push @created_classes, sort @created_messages; ## Generate Perl code of created classes if ($opts->{generate_code}) { require 'Google/ProtocolBuffers/CodeGen.pm'; my $fh; if (!ref($opts->{generate_code})) { open($fh, ">$opts->{generate_code}") or die "Can't write to '$opts->{generate_code}': $!"; } else { $fh = $opts->{generate_code}; } my $package_str = ($opts->{'package_name'}) ? "package $opts->{'package_name'};" : ""; my $source_str = ($source->{'file'}) ? "$source->{'file'}" : "inline text"; print $fh <<"HEADER"; # Generated by the protocol buffer compiler (protoc-perl) DO NOT EDIT! # source: $source_str $package_str use strict; use warnings; use Google::ProtocolBuffers; { HEADER foreach my $class_name (@created_classes) { print $fh $class_name->getPerlCode($opts); } print $fh "}\n1;\n"; } return @created_classes; } # Google::ProtocolBuffers->create_message( # 'AccountRecord', # [ # ## required string name = 1; # [LABEL_REQUIRED, TYPE_STRING, 'name', 1 ], # [LABEL_OPTIONAL, TYPE_INT32, 'id', 2 ], # ], # ); sub create_message { my $self = shift; my $class_name = shift; my $fields = shift; my $oneofs = shift; my $opts = shift; return $self->_create_message_or_group( $class_name, $fields, $oneofs, $opts, 'Google::ProtocolBuffers::Message' ); } sub create_group { my $self = shift; my $class_name = shift; my $fields = shift; my $opts = shift; return $self->_create_message_or_group( $class_name, $fields, undef, $opts, 'Google::ProtocolBuffers::Group' ); } sub _create_message_or_group { my $self = shift; my $class_name = shift; my $fields = shift; my $oneofs = shift; my $opts = shift; my $base_class = shift; ## ## Sanity checks ## 1. Class name must be a valid Perl class name ## (should we check that this class doesn't exist yet?) ## die "Invalid class name: '$class_name'" unless $class_name =~ /^[a-z_]\w*(?:::[a-z_]\w*)*$/i; ## ## my (%field_names, %field_numbers); foreach my $f (@$fields) { my ($label, $type_name, $name, $field_number, $default_value) = @$f; die Dumper $f unless $name; ## ## field names must be valid identifiers and be unique ## die "Invalid field name: '$name'" unless $name && $name =~ /^\[?[a-z_][\w\.]*\]?$/i; if ($field_names{$name}++) { die "Field '$name' is defined more than once"; } ## ## field number must be positive and unique ## die "Invalid field number: $field_number" unless $field_number>0; if ($field_numbers{$field_number}++) { die "Field number $field_number is used more than once"; } ## type is either a number (for primitive types) ## or a class name. Can't check that complex $type ## is valid, because it may not exist yet. die "Field '$name' doesn't has a type" unless $type_name; if ($type_name =~/^\d+$/) { ## ok, this is an ID of primitive type } else { die "Type '$type_name' is not valid Perl class name" unless $type_name =~ /^[a-z_]\w*(?:::[a-z_]\w*)*$/i; } die "Unknown label value: $label" unless $label==LABEL_OPTIONAL || $label==LABEL_REQUIRED || $label==LABEL_REPEATED; } ## Make a copy of values and sort them so that field_numbers increase, ## this is a requirement of protocol ## Postitional addressation of field parts is sucks, TODO: replace by hash my @field_list = sort { $a->[F_NUMBER] <=> $b->[F_NUMBER] } map { [@$_] } @$fields; my %fields_by_field_name = map { $_->[F_NAME] => $_ } @field_list; my %fields_by_field_number = map { $_->[F_NUMBER] => $_ } @field_list; my $has_oneofs = defined($oneofs) && %$oneofs; my %oneofs_rev; if ($has_oneofs) { while (my ($name, $fields) = each %$oneofs) { %oneofs_rev = (%oneofs_rev, map { $_, $name } @$fields); } } no strict 'refs'; @{"${class_name}::ISA"} = $base_class; *{"${class_name}::_pb_fields_list"} = sub { \@field_list }; *{"${class_name}::_pb_fields_by_name"} = sub { \%fields_by_field_name }; *{"${class_name}::_pb_fields_by_number"} = sub { \%fields_by_field_number }; if ($has_oneofs) { *{"${class_name}::_pb_oneofs"} = sub { $oneofs }; *{"${class_name}::_pb_oneofs_rev"} = sub { \%oneofs_rev }; } use strict; if ($opts->{create_accessors}) { no strict 'refs'; push @{"${class_name}::ISA"}, 'Class::Accessor'; if ($has_oneofs) { *{"${class_name}::new"} = \&Google::ProtocolBuffers::new; *{"${class_name}::which_oneof"} = \&Google::ProtocolBuffers::which_oneof; } *{"${class_name}::get"} = \&Google::ProtocolBuffers::get; *{"${class_name}::set"} = \&Google::ProtocolBuffers::set; use strict; if ($opts->{follow_best_practice}) { $class_name->follow_best_practice; } my @accessors = grep { /^[a-z_]\w*$/i } map { $_->[2] } @$fields; $class_name->mk_accessors(@accessors); } } sub create_enum { my $self = shift; my $class_name = shift; my $fields = shift; my $options = shift; ## ## Sanity checks ## 1. Class name must be a valid Perl class name ## (should we check that this class doesn't exist yet?) ## 2. Field names must be valid identifiers and be unique ## die "Invalid class name: '$class_name'" unless $class_name =~ /^[a-z_]\w*(?:::[a-z_]\w*)*$/i; my %names; foreach my $f (@$fields) { my ($name, $value) = @$f; die "Invalid field name: '$name'" unless $name && $name =~ /^[a-z_]\w*$/i; if ($names{$name}++) { die "Field '$name' is defined more than once"; } } ## base class and constants export no strict 'refs'; @{"${class_name}::ISA"} = "Google::ProtocolBuffers::Enum"; %{"${class_name}::EXPORT_TAGS"} = ('constants'=>[]); use strict; ## create the constants foreach my $f (@$fields) { my ($name, $value) = @$f; no strict 'refs'; *{"${class_name}::$name"} = sub { $value }; push @{ ${"${class_name}::EXPORT_TAGS"}{'constants'} }, $name; push @{"${class_name}::EXPORT_OK"}, $name; use strict; } ## create a copy of fields for introspection/code generation my @fields = map { [@$_] } @$fields; no strict 'refs'; *{"${class_name}::_pb_fields_list"} = sub { \@fields }; } ## ## Accessors ## sub getExtension { my $self = shift; my $data = (ref $self) ? $self : shift(); my $extension_name = shift; unless($extension_name){ return \%{$self->_pb_fields_by_name()}; } $extension_name =~ s/::/./g; my $key = "[$extension_name]"; my $field = $self->_pb_fields_by_name->{$key}; if ($field) { return (exists $data->{$key}) ? $data->{$key} : $field->[F_DEFAULT]; } else { my $class_name = ref $self || $self; die "There is no extension '$extension_name' in '$class_name'"; } } sub setExtension { my $self = shift; my $data = (ref $self) ? $self : shift(); my $extension_name = shift; my $value = shift; $extension_name =~ s/::/./g; my $key = "[$extension_name]"; if ($self->_pb_fields_by_name->{$key}) { $data->{$key} = $value; } else { my $class_name = ref $self || $self; die "There is no extension '$extension_name' in '$class_name'"; } } ## ## Overide the Class::Accessor new to handle oneof fields. ## sub new { my ($proto, $fields) = @_; my ($class) = ref $proto || $proto; $fields = {} unless defined $fields; my $self = bless {}, $class; ## Set the fields while (my ($key, $value) = each %$fields) { if (!defined($value)) { $self->{$key} = undef; } else { $self->set($key, $value); } } return $self; } ## ## Return which field in a oneof is set ## sub which_oneof { my $self = shift; my $oneof = shift; return undef unless $self->can('_pb_oneofs') && exists($self->_pb_oneofs->{$oneof}); foreach my $f (@{$self->_pb_oneofs->{$oneof}}) { if (defined($self->{$f})) { return $f; } } return undef; } ## ## This is for Class::Accessor read-accessors, will be ## copied to classes from Message/Group. ## If no value is set, the default one will be returned. ## sub get { my $self = shift; if (@_==1) { ## checking that $self->{$_[0]} exists is not enough, ## since undef value may be set via Class::Accessor's new, e.g: ## my $data = My::Message->new({ name => undef }) return $self->{$_[0]} if defined $self->{$_[0]}; my $field = $self->_pb_fields_by_name->{$_[0]}; return $field->[F_DEFAULT]; } elsif (@_>1) { my @rv; my $fields; foreach my $key (@_) { if (defined $self->{$key}) { push @rv, $self->{$key}; } else { $fields ||= $self->_pb_fields_by_name; push @rv, $fields->{$key}->[F_DEFAULT]; } } return @rv; } else { Carp::confess("Wrong number of arguments received."); } } sub set { my $self = shift; my $key = shift; if (@_==1) { if (defined $_[0]) { $self->{$key} = $_[0]; } else { delete $self->{$key}; } } elsif (@_>1) { $self->{$key} = [@_]; } else { Carp::confess("Wrong number of arguments received."); } # Is this a oneof field if ($self->can('_pb_oneofs_rev') && exists($self->_pb_oneofs_rev->{$key})) { foreach my $f (@{$self->_pb_oneofs->{$self->_pb_oneofs_rev->{$key}}}) { delete $self->{$f} unless $f eq $key; } } } sub _get_class_name_for{ my $self = shift; my $type_name = shift; my $opts = shift; if ($opts->{no_camel_case}) { my $class_name = $type_name; $class_name =~ s/\./::/g; return $class_name; } else { my @idents = split qr/\./, $type_name; foreach (@idents) { s/_(.)/uc($1)/ge; $_ = "\u$_"; } return join("::", @idents); } } package Google::ProtocolBuffers::Message; no warnings 'once'; ## public *encode = \&Google::ProtocolBuffers::Codec::encode; *decode = \&Google::ProtocolBuffers::Codec::decode; *setExtension = \&Google::ProtocolBuffers::setExtension; *getExtension = \&Google::ProtocolBuffers::getExtension; *getPerlCode = \&Google::ProtocolBuffers::CodeGen::generate_code_of_message_or_group; ## internal ## _pb_complex_type_kind can be removed and $class->isa('Google::ProtocolBuffers::Message') ## can be used instead, but current implementation is faster sub _pb_complex_type_kind { Google::ProtocolBuffers::Constants::MESSAGE() } # _pb_fields_list ## These 3 methods are created in # _pb_fields_by_name ## namespace of derived class # _pb_fields_by_number package Google::ProtocolBuffers::Group; *setExtension = \&Google::ProtocolBuffers::setExtension; *getExtension = \&Google::ProtocolBuffers::getExtension; *getPerlCode = \&Google::ProtocolBuffers::CodeGen::generate_code_of_message_or_group; sub _pb_complex_type_kind { Google::ProtocolBuffers::Constants::GROUP() } #_pb_fields_list #_pb_fields_by_name #_pb_fields_by_number package Google::ProtocolBuffers::Enum; use base 'Exporter'; *getPerlCode = \&Google::ProtocolBuffers::CodeGen::generate_code_of_enum; sub _pb_complex_type_kind { Google::ProtocolBuffers::Constants::ENUM() } #_pb_fields_list 1; __END__ =pod =head1 NAME Google::ProtocolBuffers - simple interface to Google Protocol Buffers =head1 SYNOPSYS ## ## Define structure of your data and create serializer classes ## use Google::ProtocolBuffers; Google::ProtocolBuffers->parse(" message Person { required string name = 1; required int32 id = 2; // Unique ID number for this person. optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phone = 4; } ", {create_accessors => 1 } ); ## ## Serialize Perl structure and print it to file ## open my($fh), ">person.dat"; binmode $fh; print $fh Person->encode({ name => 'A.U. Thor', id => 123, phone => [ { number => 1234567890 }, { number => 987654321, type=>Person::PhoneType::WORK() }, ], }); close $fh; ## ## Decode data from serialized form ## my $person; { open my($fh), "decode(<$fh>); close $fh; } print $person->{name}, "\n"; print $person->name, "\n"; ## ditto =head1 DESCRIPTION Google Protocol Buffers is a data serialization format. It is binary (and hence compact and fast for serialization) and as extendable as XML; its nearest analogues are Thrift and ASN.1. There are official mappings for C++, Java and Python languages; this library is a mapping for Perl. =head1 METHODS =head2 Google::ProtocolBuffers->parse($proto_text, \%options) =head2 Google::ProtocolBuffers->parsefile($proto_filename, \%options) Protocol Buffers is a typed protocol, so work with it starts with some kind of Interface Definition Language named 'proto'. For the description of the language, please see the official page (L) Methods 'parse' and 'parsefile' take the description of data structure as text literal or as name of the proto file correspondently. After successful compilation, Perl serializer classes are created for each message, group or enum found in proto. In case of error, these methods will die. On success, a list of names of created classes is returned. Options are given as a hash reference, the recognizable options are: =over 4 =item include_dir => [ $dir_name ] One proto file may include others, this option sets where to look for the included files. Multiple dirs should be specificed as an ARRAYREF. =item generate_code => $filename or $file_handler Compilation of proto source is a relatively slow and memory consuming operation, it is not recommended in production environment. Instead, with this option you may specify filename or filehandle where to save Perl code of created serializer classes for future use. Example: ## in helper script use Google::ProtocolBuffers; Google::ProtocolBuffers->parse( "message Foo {optional int32 a = 1; }", { generate_code => 'Foo.pm' } ); ## then, in production code use Foo; my $str = Foo->encode({a => 100}); =item create_accessors (Boolean) If this option is set, then result of 'decode' will be a blessed structure with accessor methods for each field, look at L for more info. Example: use Google::ProtocolBuffers; Google::ProtocolBuffers->parse( "message Foo { optional int32 id = 1; }", { create_accessors => 1 } ); my $foo = Foo->decode("\x{08}\x{02}"); print $foo->id; ## prints 2 $foo->id(100); ## now it is set to 100 =item follow_best_practice (Boolean) This option is from L too; it has no effect without 'create_accessors'. If set, names of getters (read accessors) will start with get_ and names of setter with set_: use Google::ProtocolBuffers; Google::ProtocolBuffers->parse( "message Foo { optional int32 id = 1; }", { create_accessors => 1, follow_best_practice => 1 } ); ## Class::Accessor provides a constructor too my $foo = Foo->new({ id => 2 }); print $foo->get_id; $foo->set_id(100); =item simple_extensions (Boolean) If this option is set, then extensions are treated as if they were regular fields in messages or groups: use Google::ProtocolBuffers; use Data::Dumper; Google::ProtocolBuffers->parse( " message Foo { optional int32 id = 1; extensions 10 to max; } extend Foo { optional string name = 10; } ", { simple_extensions=>1, create_accessors => 1 } ); my $foo = Foo->decode("\x{08}\x{02}R\x{03}Bob"); print Dumper $foo; ## { id => 2, name => 'Bob' } print $foo->id, "\n"; $foo->name("Sponge Bob"); This option is off by default because extensions live in a separate namespace and may have the same names as fields. Compilation of such proto with 'simple_extension' option will result in die. If the option is off, you have to use special accessors for extension fields - setExtension and getExtension, as in C++ Protocol Buffer API. Hash keys for extended fields in Plain Old Data structures will be enclosed in brackets: use Google::ProtocolBuffers; use Data::Dumper; Google::ProtocolBuffers->parse( " message Foo { optional int32 id = 1; extensions 10 to max; } extend Foo { optional string id = 10; // <-- id again! } ", { simple_extensions => 0, ## <-- no simple extensions create_accessors => 1, } ); my $foo = Foo->decode("\x{08}\x{02}R\x{05}Kenny"); print Dumper $foo; ## { id => 2, '[id]' => 'Kenny' } print $foo->id, "\n"; ## 2 print $foo->getExtension('id'), "\n"; ## Kenny $foo->setExtension("id", 'Kenny McCormick'); =item no_camel_case (Boolean) By default, names of created Perl classes are taken from "camel-cased" names of proto's packages, messages, groups and enums. First characters are capitalized, all underscores are removed and the characters following them are capitalized too. An example: a fully qualified name 'package_test.Message' will result in Perl class 'PackageTest::Message'. Option 'no_camel_case' turns name-mangling off. Names of fields, extensions and enum constants are not affected anyway. =item package_name (String) Package name to be put into generated Perl code; has no effect on Perl classes names and has no effect unless 'generate_code' is also set. =back =head2 MessageClass->encode($hashref) This method may be called as class or instance method. 'MessageClass' must already be created by compiler. Input is a hash reference. Output is a scalar (string) with serialized data. Unknown fields in hashref are ignored. In case of errors (e.g. required field is not set and there is no default value for the required field) an exception is thrown. Examples: use Google::ProtocolBuffers; Google::ProtocolBuffers->parse( "message Foo {optional int32 id = 1; }", {create_accessors => 1} ); my $string = Foo->encode({ id => 2 }); my $foo = Foo->new({ id => 2 }); $string = $foo->encode; ## ditto =head2 MessageClass->decode($scalar) Class method. Input: serialized data string. Output: data object of class 'MessageClass'. Unknown fields in serialized data are ignored. In case of errors (e.g. message is broken or partial) or data string is a wide-character (utf-8) string, an exception is thrown. =head1 PROTO ELEMENTS =head2 Enums For each enum in proto, a Perl class will be constructed with constants for each enum value. You may import these constants via ClassName->import(":constants") call. Please note that Perl compiler will know nothing about these constants at compile time, because this import occurs at run time, so parenthesis after constant's name are required. use Google::ProtocolBuffers; Google::ProtocolBuffers->parse( " enum Foo { FOO = 1; BAR = 2; } ", { generate_code => 'Foo.pm' } ); print Foo::FOO(), "\n"; ## fully quailified name is fine Foo->import(":constants"); print FOO(), "\n"; ## now FOO is defined in our namespace print FOO; ## <-- Error! FOO is bareword! Or, do the import inside a BEGIN block: use Foo; ## Foo.pm was generated in previous example BEGIN { Foo->import(":constants") } print FOO, "\n"; ## ok, Perl compiler knows about FOO here =head2 Groups Though group are considered deprecated they are supported by Google::ProtocolBuffers. They are like nested messages, except that nested type definition and field definition go together: use Google::ProtocolBuffers; Google::ProtocolBuffers->parse( " message Foo { optional group Bar = 1 { optional int32 baz = 1; } } ", { create_accessors => 1 } ); my $foo = Foo->new; $foo->Bar( Foo::Bar->new({ baz => 2 }) ); print $foo->Bar->baz, ", ", $foo->{Bar}->{baz}, "\n"; # 2, 2 =head2 Default values Proto file may specify a default value for a field. The default value is returned by accessor if there is no value for field or if this value is undefined. The default value is not accessible via plain old data hash, though. Default string values are always byte-strings, if you need wide-character (Unicode) string, use L. use Google::ProtocolBuffers; Google::ProtocolBuffers->parse( "message Foo {optional string name=1 [default='Kenny'];} ", {create_accessors => 1} ); ## no initial value my $foo = Foo->new; print $foo->name(), ", ", $foo->{name}, "\n"; # Kenny, (undef) ## some defined value $foo->name('Ken'); print $foo->name(), ", ", $foo->{name}, "\n"; # Ken, Ken ## empty, but still defined value $foo->name(''); print $foo->name(), ", ", $foo->{name}, "\n"; # (empty), (empty) ## undef value == default value $foo->name(undef); print $foo->name(), ", ", $foo->{name}, "\n"; # Kenny, (undef) =head2 Extensions From the point of view of serialized data, there is no difference if a field is declared as regular field or if it is extension, as far as field number is the same. That is why there is an option 'simple_extensions' (see above) that treats extensions like regular fields. From the point of view of named accessors, however, extensions live in namespace different from namespace of fields, that's why they simple names (i.e. not fully qualified ones) may conflict. (And that's why this option is off by default). The name of extensions are obtained from their fully qualified names from which leading part, most common with the class name to be extended, is stripped. Names of hash keys enclosed in brackets; arguments to methods 'getExtension' and 'setExtension' do not. Here is the self-explanatory example to the rules: use Google::ProtocolBuffers; use Data::Dumper; Google::ProtocolBuffers->parse( " package some_package; // message Plugh contains one regular field and three extensions message Plugh { optional int32 foo = 1; extensions 10 to max; } extend Plugh { optional int32 bar = 10; } message Thud { extend Plugh { optional int32 baz = 11; } } // Note: the official Google's proto compiler does not allow // several package declarations in a file (as of version 2.0.1). // To compile this example with the official protoc, put lines // above to some other file, and import that file here. package another_package; // import 'other_file.proto'; extend some_package.Plugh { optional int32 qux = 12; } ", { create_accessors => 1 } ); my $plugh = SomePackage::Plugh->decode( "\x{08}\x{01}\x{50}\x{02}\x{58}\x{03}\x{60}\x{04}" ); print Dumper $plugh; ## {foo=>1, '[bar]'=>2, '[Thud.baz]'=>3, [another_package.qux]=>4} print $plugh->foo, "\n"; ## 1 print $plugh->getExtension('bar'), "\n"; ## 2 print $plugh->getExtension('Thud.baz'), "\n"; ## 3 print $plugh->getExtension('Thud::baz'), "\n"; ## ditto Another point is that 'extend' block doesn't create new namespace or scope, so the following proto declaration is invalid: // proto: package test; message Foo { extensions 10 to max; } message Bar { extensions 10 to max; } extend Foo { optional int32 a = 10; } extend Bar { optional int32 a = 20; } // <-- Error: name 'a' in package // 'test' is already used! Well, extensions are the most complicated part of proto syntax, and I hope that you either got it or you don't need it. =head1 RUN-TIME MESSAGE CREATION You don't like to mess with proto files? Structure of your data is known at run-time only? No problem, create your serializer classes at run-time too with method Google::ProtocolBuffers->create_message('ClassName', \@fields, \%options); (Note: The order of field description parts is the same as in proto file. The API is going to change to accept named parameters, but backward compatibility will be preserved). use Google::ProtocolBuffers; use Google::ProtocolBuffers::Constants(qw/:labels :types/); ## ## proto: ## message Foo { ## message Bar { ## optional int32 a = 1 [default=12]; ## } ## required int32 id = 1; ## repeated Bar bars = 2; ## } ## Google::ProtocolBuffers->create_message( 'Foo::Bar', [ ## optional int32 a = 1 [default=12] [LABEL_OPTIONAL, TYPE_INT32, 'a', 1, '12'] ], { create_accessors => 1 } ); Google::ProtocolBuffers->create_message( 'Foo', [ [LABEL_REQUIRED, TYPE_INT32, 'id', 1], [LABEL_REPEATED, 'Foo::Bar', 'bars', 2], ], { create_accessors => 1 } ); my $foo = Foo->new({ id => 10 }); $foo->bars( Foo::Bar->new({a=>1}), Foo::Bar->new({a=>2}) ); print $foo->encode; There are methods 'create_group' and 'create_enum' also; the following constants are exported: labels (LABEL_OPTIONAL, LABEL_OPTIONAL, LABEL_REPEATED) and types (TYPE_INT32, TYPE_UINT32, TYPE_SINT32, TYPE_FIXED32, TYPE_SFIXED32, TYPE_INT64, TYPE_UINT64, TYPE_SINT64, TYPE_FIXED64, TYPE_SFIXED64, TYPE_BOOL, TYPE_STRING, TYPE_BYTES, TYPE_DOUBLE, TYPE_FLOAT). =head1 KNOWN BUGS, LIMITATIONS AND TODOs All proto options are ignored except default values for fields; extension numbers are not checked. Unknown fields in serialized data are skipped, no stream API (encoding to/decoding from file handlers) is present. Ask for what you need most. Introspection API is planned. Declarations of RPC services are currently ignored, but their support is planned (btw, which Perl RPC implementation would you recommend?) =head1 SEE ALSO Official page of Google's Protocol Buffers project (L) Protobuf-PerlXS project (L) - creates XS wrapper for C++ classes generated by official Google's compiler protoc. You have to complile XS files every time you've changed the proto description, however, this is the fastest way to work with Protocol Buffers from Perl. Protobuf-Perl project L - someday it may be part of official Google's compiler. Thrift L ASN.1 L, L and L =head1 AUTHOR, ACKNOWLEDGEMENS, COPYRIGHT Author: Igor Gariev the CSIRT Gadgets Foundation Proto grammar is based on work by Alek Storm L This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.10.0 or, at your option, any later version of Perl 5 you may have available. Google-ProtocolBuffers-0.12/lib/Google/ProtocolBuffers/Codec.pm000755 000765 000024 00000052030 12773206454 024415 0ustar00wesstaff000000 000000 package Google::ProtocolBuffers::Codec; use strict; use warnings; ## FATAL substr warnings ("substring outside of string") was intended ## to report about incomplete messages. ## However, substr("abc", 3, 1) returns chr(0) without warning. ## Thats why the code below has to check length of string and ## substring index manually use warnings FATAL => 'substr'; use Config qw/%Config/; use Google::ProtocolBuffers::Constants qw/:all/; use Encode (); use constant BROKEN_MESSAGE => "Mesage is incomplete or invalid"; use constant MAX_UINT32 => 0xffff_ffff; use constant MAX_SINT32 => 0x7fff_ffff; use constant MIN_SINT32 =>-0x8000_0000; BEGIN { ## Protocol Buffer standard requires support of 64-bit integers. ## If platform doen't support them internally, they will be emulated ## by Math::BigInt number. ## Libraries below contains identically named funtions that are either ## use native 64-bit ints or Math::BigInts my $ivsize = $Config{ivsize}; if ($ivsize>=8) { require 'Google/ProtocolBuffers/CodecIV64.pm'; } elsif ($ivsize==4) { require 'Google/ProtocolBuffers/CodecIV32.pm'; } else { die "Unsupported size of internal Perl IntegerValue: '$ivsize' bytes."; } } BEGIN { ## Floats and doubles are packed in their native format, ## which is different on big-endian and litte-endian platforms ## Maybe create and load one of two files, like CodecIV* above? my $bo = $Config{byteorder}; if ($bo =~ '^1234') { ## little-endian platform *encode_float = \&encode_float_le; *decode_float = \&decode_float_le; *encode_double = \&encode_double_le; *decode_double = \&decode_double_le; } elsif ($bo =~ '4321$') { ## big-endian *encode_float = \&encode_float_be; *decode_float = \&decode_float_be; *encode_double = \&encode_double_be; *decode_double = \&decode_double_be; } } my @primitive_type_encoders; $primitive_type_encoders[TYPE_DOUBLE] = \&encode_double; $primitive_type_encoders[TYPE_FLOAT] = \&encode_float; $primitive_type_encoders[TYPE_INT64] = \&encode_int; $primitive_type_encoders[TYPE_UINT64] = \&encode_uint; $primitive_type_encoders[TYPE_INT32] = \&encode_int; $primitive_type_encoders[TYPE_FIXED64] = \&encode_fixed64; $primitive_type_encoders[TYPE_FIXED32] = \&encode_fixed32; $primitive_type_encoders[TYPE_BOOL] = \&encode_bool; $primitive_type_encoders[TYPE_STRING] = \&encode_string; $primitive_type_encoders[TYPE_BYTES] = \&encode_string; $primitive_type_encoders[TYPE_UINT32] = \&encode_uint; $primitive_type_encoders[TYPE_ENUM] = \&encode_int; $primitive_type_encoders[TYPE_SFIXED64] = \&encode_sfixed64; $primitive_type_encoders[TYPE_SFIXED32] = \&encode_sfixed32; $primitive_type_encoders[TYPE_SINT32] = \&encode_sint; $primitive_type_encoders[TYPE_SINT64] = \&encode_sint; my @primitive_type_decoders; $primitive_type_decoders[TYPE_DOUBLE] = \&decode_double; $primitive_type_decoders[TYPE_FLOAT] = \&decode_float; $primitive_type_decoders[TYPE_INT64] = \&decode_int; $primitive_type_decoders[TYPE_UINT64] = \&decode_uint; $primitive_type_decoders[TYPE_INT32] = \&decode_int; $primitive_type_decoders[TYPE_FIXED64] = \&decode_fixed64; $primitive_type_decoders[TYPE_FIXED32] = \&decode_fixed32; $primitive_type_decoders[TYPE_BOOL] = \&decode_bool; $primitive_type_decoders[TYPE_STRING] = \&decode_string; $primitive_type_decoders[TYPE_BYTES] = \&decode_string; $primitive_type_decoders[TYPE_UINT32] = \&decode_uint; $primitive_type_decoders[TYPE_ENUM] = \&decode_int; $primitive_type_decoders[TYPE_SFIXED64] = \&decode_sfixed64; $primitive_type_decoders[TYPE_SFIXED32] = \&decode_sfixed32; $primitive_type_decoders[TYPE_SINT32] = \&decode_sint; $primitive_type_decoders[TYPE_SINT64] = \&decode_sint; my @wire_types; $wire_types[TYPE_DOUBLE] = WIRETYPE_FIXED64; $wire_types[TYPE_FLOAT] = WIRETYPE_FIXED32; $wire_types[TYPE_INT64] = WIRETYPE_VARINT; $wire_types[TYPE_UINT64] = WIRETYPE_VARINT; $wire_types[TYPE_INT32] = WIRETYPE_VARINT; $wire_types[TYPE_FIXED64] = WIRETYPE_FIXED64; $wire_types[TYPE_FIXED32] = WIRETYPE_FIXED32; $wire_types[TYPE_BOOL] = WIRETYPE_VARINT; $wire_types[TYPE_STRING] = WIRETYPE_LENGTH_DELIMITED; ## these types were removed deliberatly from the list, ## since they must be serialized by their own classes ##$wire_types[TYPE_GROUP] ##$wire_types[TYPE_MESSAGE] $wire_types[TYPE_BYTES] = WIRETYPE_LENGTH_DELIMITED; $wire_types[TYPE_UINT32] = WIRETYPE_VARINT; ## we create a special class for each enum, but these classes ## are just namespaces for constants. User can create a message ## field with type=TYPE_ENUM and integer value. $wire_types[TYPE_ENUM] = WIRETYPE_VARINT; $wire_types[TYPE_SFIXED32] = WIRETYPE_FIXED32; $wire_types[TYPE_SFIXED64] = WIRETYPE_FIXED64; $wire_types[TYPE_SINT32] = WIRETYPE_VARINT; $wire_types[TYPE_SINT64] = WIRETYPE_VARINT; ## ## Class or instance method. ## Must not be called directly, only as a method of derived class. ## ## Input: data structure (hash-ref) ## Output: in-memory string with serialized data ## ## Example: ## my $str = My::Message->encode({a => 1}); ## or ## my $message = bless {a => 1}, 'My::Message'; ## my $str = $message->encode; ## sub encode { my $self = shift; my $data = (ref $self) ? $self : shift(); ##unless (ref $data eq 'HASH') { ## my $class = ref $self || $self; ## die "Hashref was expected for $self->encode; found '$data' instead"; ##} my $buf = ''; foreach my $field (@{ $self->_pb_fields_list }) { my ($cardinality, $type, $name, $field_number, $default) = @$field; ## Check mising values and their cardinality (i.e. label): required, optional or repeated. ## For required fields, put a default value into stream, if exists, and raise an error otherwise. my $value = $data->{$name}; if (!defined $value) { if ($cardinality==LABEL_REQUIRED) { if (defined $default) { $value = $default; } else { die "Required field '$name' is missing in $self"; } } else { next; } } if (ref $value && ref $value eq 'ARRAY') { if ($cardinality!=LABEL_REPEATED) { ## Oops, several values were given for a non-repeated field. ## We'll take the last one - the specification states that ## if several (non-repeaded) fields are in a stream, ## the last one must be taken $value = $value->[-1]; } } my $is_repeated = ref $value && ref $value eq 'ARRAY'; $field_number <<= 3; no warnings 'numeric'; my $encoder = $primitive_type_encoders[$type]; use warnings; if ($encoder) { ## ## this field is one of the base types ## die $type unless exists $wire_types[$type]; if (!$is_repeated) { encode_varint($buf, $field_number | $wire_types[$type]); $encoder->($buf, $value); } else { my $key; encode_varint($key, $field_number | $wire_types[$type]); foreach my $v (@$value) { $buf .= $key; $encoder->($buf, $v); } } } else { ## ## This field is one of complex types: another message, group or enum ## my $kind = $type->_pb_complex_type_kind; if ($kind==MESSAGE) { if (!$is_repeated) { encode_varint($buf, $field_number | WIRETYPE_LENGTH_DELIMITED); my $message = $type->encode($value); encode_varint($buf, length($message)); $buf .= $message; } else { my $key; encode_varint($key, $field_number | WIRETYPE_LENGTH_DELIMITED); foreach my $v (@$value) { $buf .= $key; my $message = $type->encode($v); encode_varint($buf, length($message)); $buf .= $message; } } } elsif ($kind==ENUM) { if (!$is_repeated) { encode_varint($buf, $field_number | WIRETYPE_VARINT); encode_int($buf, $value); } else { my $key; encode_varint($key, $field_number | WIRETYPE_VARINT); foreach my $v (@$value) { $buf .= $key; encode_int($buf, $v); } } } elsif ($kind==GROUP) { if (!$is_repeated) { encode_varint($buf, $field_number | WIRETYPE_START_GROUP); $buf .= encode($type, $value); encode_varint($buf, $field_number | WIRETYPE_END_GROUP); } else { my ($start,$end); encode_varint($start, $field_number | WIRETYPE_START_GROUP); encode_varint($end, $field_number | WIRETYPE_END_GROUP); foreach my $v (@$value) { $buf .= $start; $buf .= encode($type, $v); $buf .= $end; } } } else { die "Unkown type: $type ($kind)"; } } } return $buf; } ## ## Class method. ## Must not be called directly, only as a method of derived class ## ## Input: string of serialized data ## Output: data structure (hashref) ## If serialized data contains errors, an exception will be thrown. ## ## Example: ## my $data = My::Message->decode($str); ## ## $data is now a hashref like this: {a => 1} ## sub decode { my $class = shift; ## position must be a modifiable variable (it's passed by reference ## to all decode subroutines, that call each other recursively) ## It's slightly quicker then passing it as an object attribute ## ($self->{pos}) to each method, but readability is poor. my $pos = 0; if (Encode::is_utf8($_[0])) { ## oops, wide-character string, where did you get it from? ## Should we silently encode it to utf-8 and then process ## the resulted byte-string? die "Input data string is a wide-character string"; } return _decode_partial($class, $_[0], $pos, length($_[0])); } ## ## Internal method, decodes both Messages and Groups ## Input: ## data string, ## start_position (passed by reference, this must be a variable), ## length of message ## Output: ## for Messages: data structure ## for Groups: (data structure, field number of ending group tag) ## sub _decode_partial { my $class = shift; my $length = $_[2]; my $end_position = $_[1]+$length; my $data = bless {}, $class; my $fields = $class->_pb_fields_by_number; PAIR: while ($_[1] < $end_position) { my $v = decode_varint($_[0], $_[1]); my ($field_number, $wire_type) = ($v>>3, $v&7); if ($wire_type==WIRETYPE_END_GROUP) { if ($class->_pb_complex_type_kind==GROUP) { return ($data, $field_number); } else { die "Unexpected end of group in message"; } } if (my $field = $fields->{$field_number}) { my ($cardinality, $type, $name, $field_number_, $default) = @$field; die unless $field_number_== $field_number; my $value; no warnings 'numeric'; my $decoder = $primitive_type_decoders[$type]; use warnings; if ($decoder) { if ($wire_type==WIRETYPE_LENGTH_DELIMITED && $type!=TYPE_STRING && $type!=TYPE_BYTES) { ## ## Packed Repeated Fields: ## ; sequence of encoded ## ## order is important - $_[1] changed by decode_varint() my $l = decode_varint($_[0], $_[1]); ## length of the packed field my $e = $_[1] + $l; ## last position of the field my @values; while ($_[1]<$e) { push @values, $decoder->($_[0], $_[1]); } if ($cardinality==LABEL_REPEATED) { push @{$data->{$name}}, @values; } else { $data->{$name} = $values[-1]; } next PAIR; } else { ## regular primitive value, string or byte array $value = $decoder->($_[0], $_[1]); } } else { my $kind = $type->_pb_complex_type_kind; if ($kind==MESSAGE) { my $message_length = decode_varint($_[0], $_[1]); $value = _decode_partial($type, $_[0], $_[1], $message_length); } elsif ($kind==ENUM) { $value = decode_int($_[0], $_[1]); } elsif ($kind==GROUP) { my $end_field_number; ($value, $end_field_number) = _decode_partial($type, $_[0], $_[1], $end_position-$_[1]); die unless $field_number == $end_field_number; } else { die "Unkown type: $type ($kind)"; } } if ($cardinality==LABEL_REPEATED) { push @{$data->{$name}}, $value; } else { $data->{$name} = $value; } } else { _skip_unknown_field($_[0], $_[1], $field_number, $wire_type); } } if ($class->_pb_complex_type_kind==GROUP) { die "End of group token was not found"; } else { return $data; } } ## ## Subroutines for skipping unknown fields ## ## _skip_unknown_field($buffer, $position, $field_number, $wire_type) ## $buffer is immutable ## $position will be advanced ## $field_number is for groups only, and for checks that closing group ## field_number equals to the (given) opening field_number ## $wire_type is to know lenght of field to be skipped ## Returns none ## sub _skip_unknown_field { my ($field_number, $wire_type) = ($_[2], $_[3]); if ($wire_type==WIRETYPE_VARINT) { _skip_varint($_[0], $_[1]); } elsif ($wire_type==WIRETYPE_FIXED64) { $_[1] += 8; } elsif ($wire_type==WIRETYPE_LENGTH_DELIMITED) { my $len = decode_varint($_[0], $_[1]); $_[1] += $len; } elsif ($wire_type==WIRETYPE_START_GROUP) { my $closing_field_number = _skip_until_end_of_group($_[0], $_[1]); die unless $closing_field_number==$field_number; } elsif ($wire_type==WIRETYPE_END_GROUP) { die "Unexpected end of group"; } elsif ($wire_type==WIRETYPE_FIXED32) { $_[1] += 4; } else { die "Unknown wire type $wire_type"; } } ## ## _skip_until_end_of_group($buffer, $position); ## Returns field_number of closing group tag ## sub _skip_until_end_of_group { while (1) { my $v = decode_varint($_[0], $_[1]); my ($field_number, $wire_type) = ($v>>3, $v&7); return $field_number if $wire_type==WIRETYPE_END_GROUP; _skip_unknown_field($_[0], $_[1], $field_number, $wire_type); } } ## ## _skip_varint($buffer, $position) ## Returns none sub _skip_varint { my $c = 0; my $l = length($_[0]); while (1) { die BROKEN_MESSAGE() if $_[1] >= $l; ## if $_[1]+1 > $l last if (ord(substr($_[0], $_[1]++, 1)) & 0x80) == 0; die "Varint is too long" if ++$c>=9; } } ## ## Implementations of primitive types serialization/deserialization are ## below. Some of subroutines are defined in IV32/IV64 modules. ## ## Signature of all encode_* subs: ## encode_*($buffer, $value); ## Encoded value of $value will be appended to $buffer, which is a string ## passed by reference. No meaningfull value is returned, in case of errors ## an exception it thrown. ## ## Signature of all encode_* subs: ## my $value = decode_*($buffer, $position); ## $buffer is a string passed by reference, no copy is performed and it ## is not modified. $position is a number variable passed by reference ## (index in the string $buffer where to start decoding of a value), it ## is incremented by decode_* subs. In case of errors an exception is ## thrown. ## ## Sorry for poor readability, these subroutines were optimized for speed. ## Most probably, they (and this module entirely) should be written in XS ## ## ## type: varint ## ## Our implementation of varint knows about positive numbers only. ## It's caller's responsibility to convert negative values into ## 64-bit positives ## sub encode_varint { my $v = $_[1]; die "Varint is negative" if $v < 0; my $c = 0; while ($v > 0x7F) { $_[0] .= chr( ($v&0x7F) | 0x80 ); $v >>= 7; die "Number is too long" if ++$c >= 10; } $_[0] .= chr( ($v&0x7F) ); } ## sub decode_varint - word-size sensitive ## ## type: unsigend int (32/64) ## ## sub encode_uint - word-size sensitive *encode_uint = \&encode_int; ## decode_varint always returns positive value sub decode_uint { return decode_varint(@_); } ## ## type: signed int (32/64) ## ## Signed zigzag-encode integers ## Acutally, zigzag encoded value is just ($v>0) ? $v*2 : (-$v)*2-1; ## sub decode_sint { my $v = decode_varint(@_); if ($v & 1) { ## warning: -(($v+1)>>1) may cause overflow return -(1 + (($v-1)>>1)) } else { return $v>>1; } } ## ## type: boolean ## sub encode_bool { if ($_[1]) { encode_varint($_[0], 1); } else { encode_varint($_[0], 0); } } sub decode_bool { return (decode_varint(@_)) ? 1 : 0; } ## ## type: unsigned fixed 64-bit int ## ##sub encode_fixed64 - word-size sensitive ##sub decode_fixed64 - word-size sensitive ## ## type: signed fixed 64-bit int ## ##sub encode_sfixed64 - word-size sensitive ##sub decode_sfixed64 - word-size sensitive ## ## type: double ## ## little-endian versions sub encode_double_le { $_[0] .= pack('d', $_[1]); } sub decode_double_le { die BROKEN_MESSAGE() if $_[1]+8 > length($_[0]); my $v = unpack('d', substr($_[0], $_[1], 8)); $_[1] += 8; return $v; } ## big-endian versions sub encode_double_be { $_[0] .= reverse pack('d', $_[1]); } sub decode_double_be { die BROKEN_MESSAGE() if $_[1]+8 > length($_[0]); my $v = unpack('d', reverse substr($_[0], $_[1], 8)); $_[1] += 8; return $v; } ## ## type: string and bytes ## sub encode_string { use Carp; Carp::cluck("Undefined string") unless defined $_[1]; if (Encode::is_utf8($_[1])) { ## Ops, the string has wide-characters. ## Well, encode them to utf-8 bytes. my $v = Encode::encode_utf8($_[1]); encode_varint($_[0], length($v)); $_[0] .= $v; } else { encode_varint($_[0], length($_[1])); $_[0] .= $_[1]; } } sub decode_string { my $length = decode_varint(@_); die BROKEN_MESSAGE() if $_[1]+$length > length($_[0]); my $str = substr($_[0], $_[1], $length); $_[1] += $length; return $str; } ## ## type: unsigned 32-bit ## sub encode_fixed32 { $_[0] .= pack('V', $_[1]); } sub decode_fixed32 { die BROKEN_MESSAGE() if $_[1]+4 > length($_[0]); my $v = unpack('V', substr($_[0], $_[1], 4)); $_[1] += 4; return $v; } ## ## type: signed 32-bit ## sub encode_sfixed32 { $_[0] .= pack('V', $_[1]); } sub decode_sfixed32 { die BROKEN_MESSAGE() if $_[1]+4 > length($_[0]); my $v = unpack('V', substr($_[0], $_[1], 4)); $_[1] += 4; return ($v>MAX_SINT32()) ? ($v-MAX_UINT32())-1 : $v; } ## ## type: float ## sub encode_float_le { $_[0] .= pack('f', $_[1]); } sub decode_float_le { die BROKEN_MESSAGE() if $_[1]+4 > length($_[0]); my $v = unpack('f', substr($_[0], $_[1], 4)); $_[1] += 4; return $v; } sub encode_float_be { $_[0] .= reverse pack('f', $_[1]); } sub decode_float_be { die BROKEN_MESSAGE() if $_[1]+4 > length($_[0]); my $v = unpack('f', reverse substr($_[0], $_[1], 4)); $_[1] += 4; return $v; } Google-ProtocolBuffers-0.12/lib/Google/ProtocolBuffers/CodecIV32.pm000755 000765 000024 00000007442 12773206454 025030 0ustar00wesstaff000000 000000 ## ## Warning, despite name of the file, subrotines from here belongs ## to Google::ProtocolBuffers::Codec namespace ## package Google::ProtocolBuffers::Codec; use strict; use warnings FATAL => 'substr'; use Math::BigInt; use constant TWO_IN_64 => Math::BigInt->new("0x1_0000_0000_0000_0000"); use constant MAX_SINT64 => Math::BigInt->new( "0x7FFF_FFFF_FFFF_FFFF"); ## Signature of all encode_* subs: ## encode_*($buffer, $value); ## Encoded value of $value will be appended to $buffer, which is a string ## passed by reference. No meaningfull value is returned, in case of errors ## an exception it thrown. ## ## Signature of all encode_* subs: ## my $value = decode_*($buffer, $position); ## $buffer is a string passed by reference, no copy is performed and it ## is not modified. $position is a number variable passed by reference ## (index in the string $buffer where to start decoding of a value), it ## is incremented by decode_* subs. In case of errors an exception is ## thrown. sub decode_varint { my $v = 0; my $shift = 0; my $l = length($_[0]); while (1) { die BROKEN_MESSAGE() if $_[1] >= $l; ## if $_[1]+1 > $l my $b = ord(substr($_[0], $_[1]++, 1)); if ($shift==28) { $shift = Math::BigInt->new($shift); } $v += (($b & 0x7F) << $shift); $shift += 7; last if ($b & 0x80)==0; die "Number is too long" if $shift > 63; } return $v; } sub encode_int { if ($_[1]>=0) { encode_varint($_[0], $_[1]); } else { ## We need a positive 64 bit integer, which bit representation is ## the same as of this negative value, static_cast(int64). ## 2^64 + $v === (2^64-1) + $v + 1, for $v<0 encode_varint($_[0], (TWO_IN_64+$_[1])); } } sub decode_int { my $v = decode_varint(@_); if ($v>MAX_SINT64) { return ($v - TWO_IN_64); } else { return $v; } } ## ## $_[1]<<1 is subject to overflow: a value that fit into ## Perl's int (IV) may need unsigned int (UV) to fit, ## and I don't know how to make Perl do that cast. ## sub encode_sint { if ($_[1]>=MAX_SINT32()) { encode_varint($_[0], Math::BigInt->new($_[1])<<1); } elsif ($_[1]<=MIN_SINT32()) { encode_varint($_[0], ((-Math::BigInt->new($_[1]))<<1)-1); } elsif ($_[1]>=0) { encode_varint($_[0], $_[1]<<1); } else { encode_varint($_[0], ((-$_[1])<<1)-1); } } sub encode_fixed64 { $_[0] .= pack('V', $_[1] & 0xFFFF_FFFF); $_[0] .= pack('V', ($_[1]>>16)>>16); } sub decode_fixed64 { die BROKEN_MESSAGE() if $_[1]+8 > length($_[0]); my $a = unpack('V', substr($_[0], $_[1], 4)); my $b = unpack('V', substr($_[0], $_[1]+4, 4)); $_[1] += 8; if ($b==0) { return $a } else { $b = Math::BigInt->new($b); return $a | ($b<<32); } } sub encode_sfixed64 { if ($_[1]>=0) { $_[0] .= pack('V', $_[1] & 0xFFFF_FFFF); $_[0] .= pack('V', ($_[1]>>16)>>16); } else { ## We need a positive 64 bit integer, which bit representation is ## the same as of this negative value, static_cast(int64). ## 2^64 + $v === (2^64-1) + $v + 1, for $v<0 my $v = (TWO_IN_64+$_[1]); $_[0] .= pack('V', $v & 0xFFFF_FFFF); $_[0] .= pack('V', ($v>>16)>>16); } } sub decode_sfixed64 { die BROKEN_MESSAGE() if $_[1]+8 > length($_[0]); my $a = unpack('V', substr($_[0], $_[1], 4)); my $b = unpack('V', substr($_[0], $_[1]+4, 4)); $_[1] += 8; if ($b==0) { return $a; } else { $b = (Math::BigInt->new($b)<<32) | $a; return ($b>MAX_SINT64()) ? $b-TWO_IN_64() : $b; } } 1; Google-ProtocolBuffers-0.12/lib/Google/ProtocolBuffers/CodecIV64.pm000755 000765 000024 00000007165 12773206454 025037 0ustar00wesstaff000000 000000 ## ## Warning, despite name of the file, subrotines from here belongs ## to Google::ProtocolBuffers::Codec namespace ## package Google::ProtocolBuffers::Codec; use strict; use warnings; no warnings 'numeric'; use warnings FATAL => 'substr'; use Math::BigInt; no warnings 'portable'; use constant MAX_UINT64 => 0xFFFF_FFFF_FFFF_FFFF; use constant MAX_SINT64 => 0x7FFF_FFFF_FFFF_FFFF; use constant MIN_SINT64 =>-0x8000_0000_0000_0000; ## Signature of all encode_* subs: ## encode_*($buffer, $value); ## Encoded value of $value will be appended to $buffer, which is a string ## passed by reference. No meaningfull value is returned, in case of errors ## an exception it thrown. ## ## Signature of all encode_* subs: ## my $value = decode_*($buffer, $position); ## $buffer is a string passed by reference, no copy is performed and it ## is not modified. $position is a number variable passed by reference ## (index in the string $buffer where to start decoding of a value), it ## is incremented by decode_* subs. In case of errors an exception is ## thrown. sub decode_varint { my $v = 0; my $shift = 0; my $l = length($_[0]); while (1) { die BROKEN_MESSAGE() if $_[1] >= $l; my $b = ord(substr($_[0], $_[1]++, 1)); $v += (($b & 0x7F) << $shift); $shift += 7; last if ($b & 0x80)==0; die if $shift > 63; } return $v; } ## ## Both signed and unsigned 32/64 ints are encoded by this sub. ## Must it be more restrictive and don't allow negative values for uint types? ## Moreover, should we check that the number is an integer and not a float, ## for example? And truncate int32 types to 32 bits? ## sub encode_int { if ($_[1]>=0) { encode_varint($_[0], $_[1]); } else { ## We need a positive 64 bit integer, which bit representation is ## the same as of this negative value, static_cast(int64). ## unpack('Q', pack('q', $_[1])) is slightly slower than ## 2^64 + $v === (2^64-1) + $v + 1, for $v<0 encode_varint($_[0], (MAX_UINT64+$_[1])+1); } } sub decode_int { my $v = decode_varint(@_); if ($v>MAX_SINT64()) { return ($v-MAX_UINT64())-1; } else { return $v; } } ## ## $_[1]<<1 is subject to overflow: a value that fit into ## Perl's int (IV) may need unsigned int (UV) to fit, ## and I don't know how to make Perl do that cast. ## sub encode_sint { if ($_[1]>=MAX_SINT64()) { encode_varint($_[0], Math::BigInt->new($_[1])<<1); } elsif ($_[1]<=MIN_SINT64) { encode_varint($_[0], ((-Math::BigInt->new($_[1]))<<1)-1); } elsif ($_[1]>=0) { encode_varint($_[0], $_[1]<<1); } else { encode_varint($_[0], ((-$_[1])<<1)-1); } } sub encode_fixed64 { $_[0] .= pack('V', $_[1] & 0xFFFF_FFFF); $_[0] .= pack('V', $_[1] >> 32); } sub decode_fixed64 { die BROKEN_MESSAGE() if $_[1]+8 > length($_[0]); my $a = unpack('V', substr($_[0], $_[1], 4)); my $b = unpack('V', substr($_[0], $_[1]+4, 4)); $_[1] += 8; return $a | ($b<<32); } sub encode_sfixed64 { my $v = ($_[1]<0) ? (MAX_UINT64()+$_[1])+1 : $_[1]; $_[0] .= pack('V', $v & 0xFFFF_FFFF); $_[0] .= pack('V', $v >> 32); } sub decode_sfixed64 { die BROKEN_MESSAGE() if $_[1]+8 > length($_[0]); my $a = unpack('V', substr($_[0], $_[1], 4)); my $b = unpack('V', substr($_[0], $_[1]+4, 4)); $_[1] += 8; $a |= $b<<32; if ($a>MAX_SINT64()) { return ($a-MAX_UINT64())-1; } else { return $a; } } 1; Google-ProtocolBuffers-0.12/lib/Google/ProtocolBuffers/CodeGen.pm000755 000765 000024 00000010405 12773206454 024704 0ustar00wesstaff000000 000000 package Google::ProtocolBuffers::CodeGen; use strict; use warnings; use Google::ProtocolBuffers::Constants qw/:types :labels :complex_types/; my %primitive_types = reverse ( TYPE_DOUBLE => TYPE_DOUBLE, TYPE_FLOAT => TYPE_FLOAT, TYPE_INT64 => TYPE_INT64, TYPE_UINT64 => TYPE_UINT64, TYPE_INT32 => TYPE_INT32, TYPE_FIXED64=> TYPE_FIXED64, TYPE_FIXED32=> TYPE_FIXED32, TYPE_BOOL => TYPE_BOOL, TYPE_STRING => TYPE_STRING, TYPE_GROUP => TYPE_GROUP, ## TYPE_MESSAGE=> TYPE_MESSAGE, ## should never appear, because 'message' is a 'complex type' TYPE_BYTES => TYPE_BYTES, TYPE_UINT32 => TYPE_UINT32, TYPE_ENUM => TYPE_ENUM, ## TYPE_SFIXED32=>TYPE_SFIXED32, TYPE_SFIXED64=>TYPE_SFIXED64, TYPE_SINT32 => TYPE_SINT32, TYPE_SINT64 => TYPE_SINT64, ); my %labels = reverse ( LABEL_OPTIONAL => LABEL_OPTIONAL, LABEL_REQUIRED => LABEL_REQUIRED, LABEL_REPEATED => LABEL_REPEATED, ); sub _get_perl_literal { my $v = shift; my $opts = shift; if ($v =~ /^-?\d+$/) { ## integer literal if ($v>0x7fff_ffff || $v<-0x8000_0000) { return "Math::BigInt->new('$v')"; } else { return "$v"; } } elsif ($v =~ /[-+]?\d*\.\d+([Ee][\+-]?\d+)?|[-+]?\d+[Ee][\+-]?\d+/i) { ## floating point literal return "$v"; } else { ## string literal $v =~ s/([\x00-\x1f'"\\$@%\x80-\xff])/ '\\x{' . sprintf("%02x", ord($1)) . '}' /ge; return qq["$v"]; } } sub generate_code_of_enum { my $self = shift; my $opts = shift; my $class_name = ref($self) || $self; my $fields_text; foreach my $f (@{ $self->_pb_fields_list }) { my ($name, $value) = @$f; $value = _get_perl_literal($value, $opts); $fields_text .= " ['$name', $value],\n"; } return <<"CODE"; unless ($class_name->can('_pb_fields_list')) { Google::ProtocolBuffers->create_enum( '$class_name', [ $fields_text ] ); } CODE } sub generate_code_of_message_or_group { my $self = shift; my $opts = shift; my $create_what = ($self->_pb_complex_type_kind==MESSAGE) ? 'create_message' : ($self->_pb_complex_type_kind==GROUP) ? 'create_group' : die; my $class_name = ref($self) || $self; my $fields_text = ''; # may be empty, as empty messages are allowed foreach my $f (@{ $self->_pb_fields_list }) { my ($label, $type, $name, $field_number, $default_value) = @$f; die unless $labels{$label}; $label = "Google::ProtocolBuffers::Constants::$labels{$label}()"; if ($primitive_types{$type}) { $type = "Google::ProtocolBuffers::Constants::$primitive_types{$type}()"; } else { $type = "'$type'"; } $default_value = (defined $default_value) ? _get_perl_literal($default_value, $opts) : 'undef'; $fields_text .= <<"FIELD"; [ $label, $type, '$name', $field_number, $default_value ], FIELD } my $oneofs_text = " undef,\n"; if ($self->can('_pb_oneofs')) { $oneofs_text = " {\n"; while (my ($name, $fields) = each %{$self->_pb_oneofs}) { $oneofs_text .= " '$name' => [\n"; foreach my $f (@$fields) { $oneofs_text .= " '$f',\n"; } $oneofs_text .= " ],\n"; } $oneofs_text .= " },\n"; } my $options = ''; foreach my $opt_name (qw/create_accessors follow_best_practice/) { if ($opts->{$opt_name}) { $options .= "'$opt_name' => 1, " } } return <<"CODE"; unless ($class_name->can('_pb_fields_list')) { Google::ProtocolBuffers->$create_what( '$class_name', [ $fields_text ], $oneofs_text { $options } ); } CODE } 1; Google-ProtocolBuffers-0.12/lib/Google/ProtocolBuffers/Compiler.pm000755 000765 000024 00000060252 12773206454 025157 0ustar00wesstaff000000 000000 package Google::ProtocolBuffers::Compiler; use strict; use warnings; use Parse::RecDescent; use Data::Dumper; use Google::ProtocolBuffers::Constants qw/:types :labels/; use Carp; use Config qw/%Config/; use File::Spec; ## ## Grammar is based on work by Alek Storm ## http://groups.google.com/group/protobuf/browse_thread/thread/1cccfc624cd612da ## http://groups.google.com/group/protobuf/attach/33102cfc0c57d449/proto2.ebnf?part=4 ## my $grammar = <<'END_OF_GRAMMAR'; proto : ## list of top level declarations. ## Skip empty declarations and ";". (message | extend | enum | import | package | option | service | syntax | ";")(s) /\Z/ { $return = [ grep {ref $_} @{$item[2]} ]; } | import : "import" strLit ";" { $return = [ import => $item{strLit} ]; } ## error? reject pair means: ## if rule was commited (i.e. "import" was found), then fail the entire parse ## otherwise, just skip this production (and try another one) | package : "package" qualifiedIdent ";" { $return = [ package => $item{qualifiedIdent} ]; } | option : ## so far, options are ignored "option" optionBody ";" { $return = '' } | optionBody : qualifiedIdent "=" constant { $return = '' } message : "message" ident messageBody { $return = [ message => $item{ident}, $item{messageBody} ]; } | extend : "extend" userType "{" ( field | group | ";" )(s?) "}" { $return = [extend => $item{userType}, [ grep {ref $_} @{$item[5]}] ]} enum : "enum" ident "{" (option | enumField | ";")(s) "}" { $return = [ enum => $item{ident}, [grep {ref $_} @{$item[5]}] ] } | enumField : ident "=" intLit ";" { $return = [ enumField => $item{ident}, $item{intLit} ] } service : ## services are ignored "service" ident "{" ( option | rpc | ";" )(s?) "}" { $return = '' } | rpc : "rpc" ident "(" userType ")" "returns" "(" userType ")" rpcOptions(?) ";" { $return = '' } | rpcOptions : "{" option(s?) "}" messageBody : "{" ( field | enum | message | extend | extensions | group | option | oneof | ";" )(s?) "}" { $return = [ grep {ref $_} @{$item[3]} ] } | group : label "group" ident "=" intLit messageBody { $return = [group => $item{label}, $item{ident}, $item{intLit}, $item{messageBody} ] } | field : label type ident "=" intLit fOptList(?) ";" { $return = [field => $item{label}, $item{type}, $item{ident}, $item{intLit}, $item[6][0] ] } oneof : "oneof" ident "{" ( oneofField | ";" )(s?) "}" { $return = [ oneof => $item{ident}, [grep {ref $_} @{$item[5]}] ] } | oneofField : type ident "=" intLit fOptList(?) ";" { $return = [field => "optional", $item{type}, $item{ident}, $item{intLit}, $item[5][0] ] } fOptList : "[" fieldOption(s? /,/) "]" { $return = (grep {length($_)} @{$item[2]})[0] || '' } fieldOption : "default" "=" constant { $return = $item{constant} } | optionBody { $return = '' } | extensions : "extensions" extension(s /,/) ";" { $return = '' } | extension : intLit ( "to" ( intLit | "max" ) )(s?) { $return = '' } label : "required" | "optional" | "repeated" type : "double" | "float" | "int32" | "int64" | "uint32" | "uint64" | "sint32" | "sint64" | "fixed32" | "fixed64" | "sfixed32" | "sfixed64" | "bool" | "string" | "bytes" | userType userType : (".")(?) qualifiedIdent { $return = ($item[1] && @{$item[1]}) ? ".$item[2]" : $item[2] } constant : ident { $return = $item[1]; } | (floatLit | intLit | strLit | boolLit) { $return = { value => $item[1] } } ident : /[a-z_]\w*/i qualifiedIdent: { $return = join(".", @{ $item[1] })} intLit : hexInt | octInt| decInt decInt : /[-+]?[1-9]\d*/ { $return = Google::ProtocolBuffers::Compiler::get_dec_int($item[1]) } hexInt : /[-+]?0[xX]([A-Fa-f0-9])+/ { $return = Google::ProtocolBuffers::Compiler::get_hex_int($item[1]) } octInt : /[-+]?0[0-7]*/ { $return = Google::ProtocolBuffers::Compiler::get_oct_int($item[1]) } floatLit : ## Make floatLit do not match integer literals, ## so that it doesn't take off '0' from '0xFFF' or '012' (oct). /[-+]?\d*\.\d+([Ee][\+-]?\d+)?/ | /[-+]?\d+[Ee][\+-]?\d+/ boolLit : "true" { $return = 1 } | "false" { $return = 0 } strLit : /['"]/ ( hexEscape | octEscape | charEscape | regularChar)(s?) /['"]/ { $return = join('', @{$item[3]}) } regularChar : ## all chars exept chr(0) and "\n" /[^\0\n'"]/ hexEscape : /\\[Xx]/ /[A-Fa-f0-9]{1,2}/ { $return = chr(hex($item[2])) } octEscape : '\\' /^0?[0-7]{1,3}/ { $return = chr(oct("0$item[2]") & 0xFF); } charEscape : /\\[abfnrtv\\'"]/ { my $s = substr($item[1], 1, 1); $return = ($s eq 'a') ? "\a" : ($s eq 'b') ? "\b" : ($s eq 'f') ? "\f" : ($s eq 'n') ? "\n" : ($s eq 'r') ? "\r" : ($s eq 't') ? "\t" : ($s eq 'v') ? "\x0b" : $s; } syntax : "syntax" "=" strLit ## syntax = "proto2"; { die "Unknown syntax" unless $item{strLit} eq 'proto2'; $return = ''; } END_OF_GRAMMAR my %primitive_types = ( "double" => TYPE_DOUBLE, "float" => TYPE_FLOAT, "int32" => TYPE_INT32, "int64" => TYPE_INT64, "uint32" => TYPE_UINT32, "uint64" => TYPE_UINT64, "sint32" => TYPE_SINT32, "sint64" => TYPE_SINT64, "fixed32" => TYPE_FIXED32, "fixed64" => TYPE_FIXED64, "sfixed32" => TYPE_SFIXED32, "sfixed64" => TYPE_SFIXED64, "bool" => TYPE_BOOL, "string" => TYPE_STRING, "bytes" => TYPE_BYTES, ); my %labels = ( 'required' => LABEL_REQUIRED, 'optional' => LABEL_OPTIONAL, 'repeated' => LABEL_REPEATED, ); my $has_64bit = $Config{ivsize}>=8; sub _get_int_value { my $str = shift; my $max_pos_str = shift; my $max_neg_str = shift; my $str_to_num = shift; my $str_to_bigint = shift; my $is_negative = ($str =~/^-/); $str =~ s/^[+-]//; if (!$has_64bit) { my $l = length($str); if ( !$is_negative && ($l>length($max_pos_str) || ($l==length($max_pos_str) && uc($str) ge uc($max_pos_str))) || $is_negative && ( $l>length($max_neg_str) || ($l==length($max_neg_str) && uc($str) ge uc($max_neg_str))) ) { my $v = $str_to_bigint->($str); return ($is_negative) ? -$v : $v; } } my $v = $str_to_num->($str); return ($is_negative) ? -$v : $v; } sub get_dec_int { my $str = shift; return _get_int_value( $str, "2147483647", "2147483648", sub { no warnings 'portable'; return $_[0]+0; }, sub { return Math::BigInt->new($_[0]); } ); } sub get_hex_int { my $str = shift; return _get_int_value( $str, "0x7fffffff", "0x80000000", sub { no warnings 'portable'; return hex($_[0]); }, sub { return Math::BigInt->new($_[0]); } ); } sub get_oct_int { my $str = shift; return _get_int_value( $str, "017777777777", "020000000000", sub { no warnings 'portable'; return oct($_[0]); }, sub { ## oops, Math::BigInt doesn't accept strings of octal digits, ## ... but accepts binary digits my $v = shift; my @oct_2_binary = qw(000 001 010 011 100 101 110 111); $v =~ s/(.)/$oct_2_binary[$1]/g; return Math::BigInt->new('0b' . $v); } ); } sub parse { my $class = shift; my $source = shift; my $opts = shift; my $self = bless { opts => $opts }; $::RD_ERRORS = 1; $::RD_WARN = 1; my $parser = Parse::RecDescent->new($grammar) or die; ## all top level declarations from all files (files be included) ## will be here my @parse_tree; my (@import_files, $text); if ($source->{text}) { $text = $source->{text}; } elsif ($source->{file}) { @import_files = ('', $source->{file}); } else { die; } my %already_included_files; while ($text || @import_files) { my ($content, $filename); if ($text) { $content = $text; undef $text; } else { ## path may be relative to the path of the file, where ## "import" directive. Also, root dir for proto files ## may be specified in options my ($root, $path) = splice(@import_files, 0, 2); $filename = $self->_find_filename($root, $path); next if $already_included_files{$filename}++; { my $fh; open $fh, $filename or die "Can't read from $filename: $!"; local $/; $content = <$fh>; close $fh; } } my $res = $parser->proto($content); die "" unless defined $res; ## start each file from empty package push @parse_tree, [package=>'']; foreach my $decl (@$res) { if ($decl->[0] eq 'import') { push @import_files, ($filename, $decl->[1]); } else { push @parse_tree, $decl; } } } ## ## Pass #1. ## Find names of messages and enums, including nested ones. ## my $symbol_table = Google::ProtocolBuffers::Compiler::SymbolTable->new; $self->{symbol_table} = $symbol_table; $self->collect_names('', \@parse_tree); ## ## Pass #2. ## Create complete descriptions of messages with extensions. ## For each field of a user type a fully quilified type name must be found. ## For each default value defined by a constant (enum), a f.q.n of enum value must be found ## foreach my $kind (qw/message group enum oneof/) { foreach my $fqname ($symbol_table->lookup_names_of_kind($kind)) { $self->{types}->{$fqname} = { kind => $kind, fields => [], extensions => [], oneofs => [] }; } } $self->collect_fields('', \@parse_tree); return $self->{types}; } sub _find_filename { my $self = shift; my $base_filename = shift; my $path = shift; =comment my $filename = File::Spec->rel2abs($path, $base_filename); return $filename if -e $filename; if ($self->{opts}->{include_dir}) { $filename = File::Spec->rel2abs($path, $self->{opts}->{include_dir}); return $filename if -e $filename; } =cut use Cwd; my $d = getcwd(); my $filename = $path; return $filename if -e $filename; if (my $inc_dirs = $self->{opts}->{include_dir}) { $inc_dirs = [ $inc_dirs ] unless(ref($inc_dirs) eq 'ARRAY'); foreach my $d (@$inc_dirs){ $filename = File::Spec->catfile($d, $path); return $filename if -e $filename; } } die "Can't find proto file: '$path'"; } sub collect_names { my $self = shift; my $context = shift; my $nodes = shift; my $symbol_table = $self->{symbol_table}; foreach my $decl (@$nodes) { my $kind = $decl->[0]; ## 'message', 'extent', 'enum' etc... if ($kind eq 'package') { ## package directive just set new context, ## not related to previous one $context = $symbol_table->set_package($decl->[1]); } elsif ($kind eq 'message') { ## message may include nested messages/enums/groups/oneofs my $child_context = $symbol_table->add('message' => $decl->[1], $context); $self->collect_names($child_context, $decl->[2]); } elsif ($kind eq 'enum') { my $child_context = $symbol_table->add('enum' => $decl->[1], $context); $self->collect_names($child_context, $decl->[2]); } elsif ($kind eq 'group') { ## there may be nested messages/enums/groups/oneofs etc. inside group ## [group => $label, $ident, $intLit, $messageBody ] my $child_context = $symbol_table->add('group' => $decl->[2], $context); $self->collect_names($child_context, $decl->[4]); } elsif ($kind eq 'oneof') { ## OneOfs may only contain fields, we add them to both ## the current and oneof context my $child_context = $symbol_table->add('oneof' => $decl->[1], $context); foreach my $oneof (@{$decl->[2]}) { $symbol_table->add('field' => $oneof->[3], $context); $symbol_table->add('field' => $oneof->[3], $child_context); } } elsif ($kind eq 'extend') { ## extend blocks are tricky: ## 1) they don't create a new scope ## 2) there may be a group inside extend block, and there may be everything inside the group $self->collect_names($context, $decl->[2]); } elsif ($kind eq 'field') { ## we add fields into symbol table just to check their uniqueness ## in several extension blocks or oneofs. Example: ## .proto: ## extend A { required int32 foo = 100 }; ## extend B { required int32 foo = 200 }; ## // Invalid! foo is already declared! ## $symbol_table->add('field' => $decl->[3], $context); } elsif ($kind eq 'enumField') { $symbol_table->add('enum_field' => $decl->[1], $context); } else { warn $kind; } } } sub collect_fields { my $self = shift; my $context = shift; my $nodes = shift; my $destination_type_name = shift; my $is_extension = shift; my $symbol_table = $self->{symbol_table}; foreach my $decl (@$nodes) { my $kind = $decl->[0]; ## 'message', 'extent', 'enum' etc... if ($kind eq 'package') { $context = $decl->[1]; } elsif ($kind eq 'message') { my $child_context = ($context) ? "$context.$decl->[1]" : $decl->[1]; $self->collect_fields($child_context, $decl->[2], $child_context); } elsif ($kind eq 'enum') { my $child_context = ($context) ? "$context.$decl->[1]" : $decl->[1]; $self->collect_fields($child_context, $decl->[2], $child_context); } elsif ($kind eq 'group') { ## groups are tricky: they are both definition of a field and type. ## [group => $label, $ident, $intLit, $messageBody ] ## first, collect fields inside the group my $child_context = ($context) ? "$context.$decl->[2]" : $decl->[2]; $self->collect_fields($child_context, $decl->[4], $child_context); ## second, add the group as one field to parent (destination) type confess unless $destination_type_name; my $name; my $fields_list; if ($is_extension) { ## for extensions, fully quilified names of fields are used, ## because they may be declared anywhere - even in another package $fields_list = $self->{types}->{$destination_type_name}->{extensions}; $name = $symbol_table->lookup('group' => $decl->[2], $context); } else { ## regualar fields are always immediate children of their type $fields_list = $self->{types}->{$destination_type_name}->{fields}; $name = $decl->[2]; } my $label = (exists $labels{$decl->[1]}) ? $labels{$decl->[1]} : die; my ($type_name, $kind) = $symbol_table->lookup_symbol($decl->[2], $context); die unless $kind eq 'group'; my $field_number = $decl->[3]; push @$fields_list, [$label, $type_name, $name, $field_number]; } elsif ($kind eq 'oneof') { my $child_context = ($context) ? "$context.$decl->[1]" : $decl->[1]; $self->collect_fields($child_context, $decl->[2], $child_context); push @{$self->{types}->{$destination_type_name}->{oneofs}}, $child_context; } elsif ($kind eq 'extend') { ## what is the fqn of the message to be extended? my $destination_message = $symbol_table->lookup('message' => $decl->[1], $context); $self->collect_fields($context, $decl->[2], $destination_message, 1); } elsif ($kind eq 'field') { confess unless $destination_type_name; # $decl = ['field' => $label, $type, $ident, $item{intLit}, $item{fOptList}] } my $name; my $fields_list; if ($is_extension) { ## for extensions, fully quilified names of fields are used, ## because they may be declared anywhere - even in another package $fields_list = $self->{types}->{$destination_type_name}->{extensions}; $name = $symbol_table->lookup('field' => $decl->[3], $context); } else { ## regualar fields are always immediate children of their type $fields_list = $self->{types}->{$destination_type_name}->{fields}; $name = $decl->[3]; } my $label = (exists $labels{$decl->[1]}) ? $labels{$decl->[1]} : die; my ($type_name, $kind); if (exists $primitive_types{$decl->[2]}) { $type_name = $primitive_types{$decl->[2]}; } else { ($type_name, $kind) = $symbol_table->lookup_symbol($decl->[2], $context); die unless $kind eq 'message' || $kind eq 'group' || $kind eq 'enum'; } my $field_number = $decl->[4]; my $default_value = $decl->[5]; if ($default_value && !ref $default_value) { if ($default_value eq 'true') { $default_value = { value => 1 }; } elsif ($default_value eq 'false') { $default_value = { value => 0 }; } else { ## this default is enum value ## type name must be fqn of enum type die unless $kind eq 'enum'; $default_value = $symbol_table->lookup('enum_field' => $default_value, $type_name); } } push @$fields_list, [$label, $type_name, $name, $field_number, $default_value]; } elsif ($kind eq 'enumField') { confess unless $destination_type_name; my $fields_list = $self->{types}->{$destination_type_name}->{fields}; push @{$fields_list}, [$decl->[1], $decl->[2]]; } else { warn $kind; } } } package Google::ProtocolBuffers::Compiler::SymbolTable; ## ## %$self - symbol name table, descriptions of fully qualified names like Foo.Bar: ## $names{'foo'} = { kind => 'package' } ## $names{'foo.Bar'} = { kind => 'message' } ## $names{'foo.Bar.Baz'}={ kind => 'enum', } ## use Data::Dumper; use Carp; sub new { my $class = shift; return bless {}, $class; } sub set_package { my $self = shift; my $package = shift; return '' unless $package; my @idents = split qr/\./, $package; my $name = shift @idents; while (1) { if (exists $self->{$name}) { die unless $self->{$name}->{kind} eq 'package'; } else { $self->{$name} = {kind => 'package'} } last unless @idents; $name .= '.' . shift(@idents); } return $name; } sub _add { my $self = shift; my $kind = shift; my $name = shift; my $context = shift; ## no fully quilified names are alowed to declare (so far) die if $name =~ /\./; my $fqn; if ($context) { die "$name, $context" unless $self->{$context}; $fqn = "$context.$name"; } else { $fqn = $name; } if (exists $self->{$fqn}) { die "Name '$fqn' is already defined"; } else { $self->{$fqn} = { kind=>$kind }; } return $fqn; } sub add { my $self = shift; my $kind = shift; my $name = shift; my $context = shift; ## tricky: enum values are both children and siblings of enums if ($kind eq 'enum_field') { die unless $self->{$context}->{kind} eq 'enum'; my $fqn = $self->_add($kind, $name, $context); $context =~ s/(^|\.)\w+$//; ## parent context $self->_add($kind, $name, $context); return $fqn; } else { return $self->_add($kind, $name, $context); } } ## input: fully or partially qualified name ## output: (fully qualified name, its kind - 'message', 'enum_field' etc.) sub lookup_symbol { my $self = shift; my $n = shift; my $c = shift; my $context = $c; my $name = $n; if ($name =~ s/^\.//) { ## this is an fully quialified name if (exists $self->{$name}) { return ($name, $self->{$name}->{kind}); } } else { ## relative name - look it up in the current context and up while (1) { my $fqn = ($context) ? "$context.$name" : $name; if (exists $self->{$fqn}) { return ($fqn, $self->{$fqn}->{kind}); } ## one level up last unless $context; $context =~ s/(^|\.)\w+$//; } } die "Name '$name' ($c, $n) is not defined" . Data::Dumper::Dumper($self); } ## input: kind, fully or partially qualified name, context ## ouptut: fully qualified name ## if found kind of the name doesn't match given kind, an exception is raised sub lookup { my $self = shift; my $kind = shift; my $name = shift; my $context = shift; my ($fqn, $k) = $self->lookup_symbol($name, $context); unless ($kind eq $k) { confess "Error: while looking for '$kind' named '$name' in '$context', a '$k' named '$fqn' was found"; } return $fqn; } ## returns list of all fully qualified name of a given kind sub lookup_names_of_kind { my $self = shift; my $kind = shift; return grep { $self->{$_}->{kind} eq $kind } keys %$self; } 1; Google-ProtocolBuffers-0.12/lib/Google/ProtocolBuffers/Constants.pm000755 000765 000024 00000006233 12773206454 025360 0ustar00wesstaff000000 000000 package Google::ProtocolBuffers::Constants; use strict; use warnings; my ($types, $wiretypes, $labels, $complex_types); BEGIN { ## from src/google/protobuf/descriptor.h $types = { TYPE_DOUBLE => 1, ## double, exactly eight bytes on the wire. TYPE_FLOAT => 2, ## float, exactly four bytes on the wire. TYPE_INT64 => 3, ## int64, varint on the wire. Negative numbers ## take 10 bytes. Use TYPE_SINT64 if negative ## values are likely. TYPE_UINT64 => 4, ## uint64, varint on the wire. TYPE_INT32 => 5, ## int32, varint on the wire. Negative numbers ## take 10 bytes. Use TYPE_SINT32 if negative ## values are likely. TYPE_FIXED64 => 6, ## uint64, exactly eight bytes on the wire. TYPE_FIXED32 => 7, ## uint32, exactly four bytes on the wire. TYPE_BOOL => 8, ## bool, varint on the wire. TYPE_STRING => 9, ## UTF-8 text. TYPE_GROUP => 10, ## Tag-delimited message. Deprecated. TYPE_MESSAGE => 11, ## Length-delimited message. TYPE_BYTES => 12, ## Arbitrary byte array. TYPE_UINT32 => 13, ## uint32, varint on the wire TYPE_ENUM => 14, ## Enum, varint on the wire TYPE_SFIXED32 => 15, ## int32, exactly four bytes on the wire TYPE_SFIXED64 => 16, ## int64, exactly eight bytes on the wire TYPE_SINT32 => 17, ## int32, ZigZag-encoded varint on the wire TYPE_SINT64 => 18, ## int64, ZigZag-encoded varint on the wire }; ## from src/google/protobuf/descriptor.h $labels = { LABEL_OPTIONAL => 1, LABEL_REQUIRED => 2, LABEL_REPEATED => 3, }; ## from src/google/protobuf/wire_format.h $wiretypes = { WIRETYPE_VARINT => 0, WIRETYPE_FIXED64 => 1, WIRETYPE_LENGTH_DELIMITED => 2, WIRETYPE_START_GROUP => 3, WIRETYPE_END_GROUP => 4, WIRETYPE_FIXED32 => 5, }; ## Complex types - this is not a part of Google specificaion $complex_types = { MESSAGE => 1, GROUP => 2, ENUM => 3, ONEOF => 4, }; } use base 'Exporter'; use vars qw/@EXPORT_OK %EXPORT_TAGS/; use constant $types; $EXPORT_TAGS{'types'} = [keys %$types]; push @{$EXPORT_TAGS{'all'}}, keys %$types; push @EXPORT_OK, keys %$types; use constant $wiretypes; $EXPORT_TAGS{'wiretypes'} = [keys %$wiretypes]; push @{$EXPORT_TAGS{'all'}}, keys %$wiretypes; push @EXPORT_OK, keys %$wiretypes; use constant $labels; $EXPORT_TAGS{'labels'} = [keys %$labels]; push @{$EXPORT_TAGS{'all'}}, keys %$labels; push @EXPORT_OK, keys %$labels; use constant $complex_types; $EXPORT_TAGS{'complex_types'} = [keys %$complex_types]; push @{$EXPORT_TAGS{'all'}}, keys %$complex_types; push @EXPORT_OK, keys %$complex_types; 1; Google-ProtocolBuffers-0.12/bin/protoc-perl000755 000765 000024 00000004100 12773206454 020676 0ustar00wesstaff000000 000000 #!/usr/bin/env perl use strict; use warnings; use Getopt::Long; Getopt::Long::Configure("pass_through"); use Data::Dumper; use Google::ProtocolBuffers; our $VERSION = $Google::ProtocolBuffers::VERSION; my $path = []; my $help = 0; my $debug = 0; my $verbose = 0; my $version = 0; my $decode_raw = 0; my $oFile = 0; my $perl_out = 0; my $package_name = ''; my $proto_file = 0; GetOptions( 'proto_path|I=s@' => \$path, 'help|h' => \$help, 'debug|d' => \$debug, 'verbose+' => \$verbose, 'perl_out=s' => \$perl_out, 'version|v' => \$version, 'package|p=s' => \$package_name, ); ## TODO: multi-proto support $proto_file = $ARGV[$#ARGV]; pop(@ARGV); # test for -Ilib foreach (@ARGV){ if(/^-I/){ $_ =~ s/^-I//; push(@{$path},$_); } } if($version){ print "Google::ProtocolBuffers ".$VERSION."\n"; exit(0); } die usage() if($help || !$proto_file); sub usage { return <parsefile( $proto_file, { generate_code => $perl_out, create_accessors => 1, follow_best_practice => 1, include_dir => $path, package_name => $package_name, } );