blob: a5a31156faf047c063dc676f5a282eb41a7c2bf1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef _THRIFT_TEST_GENERICPROTOCOLTEST_TCC_
#define _THRIFT_TEST_GENERICPROTOCOLTEST_TCC_ 1
#include <limits>
#include <protocol/TBinaryProtocol.h>
#include <transport/TBufferTransports.h>
#include <Thrift.h>
#include "GenericHelpers.h"
using boost::shared_ptr;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
#define ERR_LEN 512
extern char errorMessage[ERR_LEN];
template <typename TProto, typename Val>
void testNaked(Val val) {
shared_ptr<TTransport> transport(new TMemoryBuffer());
shared_ptr<TProtocol> protocol(new TProto(transport));
GenericIO::write(protocol, val);
Val out;
GenericIO::read(protocol, out);
if (out != val) {
snprintf(errorMessage, ERR_LEN, "Invalid naked test (type: %s)", ClassNames::getName<Val>());
throw TException(errorMessage);
}
}
template <typename TProto, TType type, typename Val>
void testField(const Val val) {
shared_ptr<TTransport> transport(new TMemoryBuffer());
shared_ptr<TProtocol> protocol(new TProto(transport));
protocol->writeStructBegin("test_struct");
protocol->writeFieldBegin("test_field", type, (int16_t)15);
GenericIO::write(protocol, val);
protocol->writeFieldEnd();
protocol->writeStructEnd();
std::string name;
TType fieldType;
int16_t fieldId;
protocol->readStructBegin(name);
protocol->readFieldBegin(name, fieldType, fieldId);
if (fieldId != 15) {
snprintf(errorMessage, ERR_LEN, "Invalid ID (type: %s)", typeid(val).name());
throw TException(errorMessage);
}
if (fieldType != type) {
snprintf(errorMessage, ERR_LEN, "Invalid Field Type (type: %s)", typeid(val).name());
throw TException(errorMessage);
}
Val out;
GenericIO::read(protocol, out);
if (out != val) {
snprintf(errorMessage, ERR_LEN, "Invalid value read (type: %s)", typeid(val).name());
throw TException(errorMessage);
}
protocol->readFieldEnd();
protocol->readStructEnd();
}
template <typename TProto>
void testMessage() {
struct TMessage {
const char* name;
TMessageType type;
int32_t seqid;
} messages[4] = {
{"short message name", T_CALL, 0},
{"1", T_REPLY, 12345},
{"loooooooooooooooooooooooooooooooooong", T_EXCEPTION, 1 << 16},
{"Janky", T_CALL, 0}
};
for (int i = 0; i < 4; i++) {
shared_ptr<TTransport> transport(new TMemoryBuffer());
shared_ptr<TProtocol> protocol(new TProto(transport));
protocol->writeMessageBegin(messages[i].name,
messages[i].type,
messages[i].seqid);
protocol->writeMessageEnd();
std::string name;
TMessageType type;
int32_t seqid;
protocol->readMessageBegin(name, type, seqid);
if (name != messages[i].name ||
type != messages[i].type ||
seqid != messages[i].seqid) {
throw TException("readMessageBegin failed.");
}
}
}
template <typename TProto>
void testProtocol(const char* protoname) {
try {
testNaked<TProto, int8_t>((int8_t)123);
for (int32_t i = 0; i < 128; i++) {
testField<TProto, T_BYTE, int8_t>((int8_t)i);
testField<TProto, T_BYTE, int8_t>((int8_t)-i);
}
testNaked<TProto, int16_t>((int16_t)0);
testNaked<TProto, int16_t>((int16_t)1);
testNaked<TProto, int16_t>((int16_t)15000);
testNaked<TProto, int16_t>((int16_t)0x7fff);
testNaked<TProto, int16_t>((int16_t)-1);
testNaked<TProto, int16_t>((int16_t)-15000);
testNaked<TProto, int16_t>((int16_t)-0x7fff);
testNaked<TProto, int16_t>(std::numeric_limits<int16_t>::min());
testNaked<TProto, int16_t>(std::numeric_limits<int16_t>::max());
testField<TProto, T_I16, int16_t>((int16_t)0);
testField<TProto, T_I16, int16_t>((int16_t)1);
testField<TProto, T_I16, int16_t>((int16_t)7);
testField<TProto, T_I16, int16_t>((int16_t)150);
testField<TProto, T_I16, int16_t>((int16_t)15000);
testField<TProto, T_I16, int16_t>((int16_t)0x7fff);
testField<TProto, T_I16, int16_t>((int16_t)-1);
testField<TProto, T_I16, int16_t>((int16_t)-7);
testField<TProto, T_I16, int16_t>((int16_t)-150);
testField<TProto, T_I16, int16_t>((int16_t)-15000);
testField<TProto, T_I16, int16_t>((int16_t)-0x7fff);
testNaked<TProto, int32_t>(0);
testNaked<TProto, int32_t>(1);
testNaked<TProto, int32_t>(15000);
testNaked<TProto, int32_t>(0xffff);
testNaked<TProto, int32_t>(-1);
testNaked<TProto, int32_t>(-15000);
testNaked<TProto, int32_t>(-0xffff);
testNaked<TProto, int32_t>(std::numeric_limits<int32_t>::min());
testNaked<TProto, int32_t>(std::numeric_limits<int32_t>::max());
testField<TProto, T_I32, int32_t>(0);
testField<TProto, T_I32, int32_t>(1);
testField<TProto, T_I32, int32_t>(7);
testField<TProto, T_I32, int32_t>(150);
testField<TProto, T_I32, int32_t>(15000);
testField<TProto, T_I32, int32_t>(31337);
testField<TProto, T_I32, int32_t>(0xffff);
testField<TProto, T_I32, int32_t>(0xffffff);
testField<TProto, T_I32, int32_t>(-1);
testField<TProto, T_I32, int32_t>(-7);
testField<TProto, T_I32, int32_t>(-150);
testField<TProto, T_I32, int32_t>(-15000);
testField<TProto, T_I32, int32_t>(-0xffff);
testField<TProto, T_I32, int32_t>(-0xffffff);
testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::min());
testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::max());
testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::min() + 10);
testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::max() - 16);
testNaked<TProto, int64_t>(std::numeric_limits<int64_t>::min());
testNaked<TProto, int64_t>(std::numeric_limits<int64_t>::max());
testNaked<TProto, int64_t>(0);
for (int64_t i = 0; i < 62; i++) {
testNaked<TProto, int64_t>(1L << i);
testNaked<TProto, int64_t>(-(1L << i));
}
testField<TProto, T_I64, int64_t>(0);
for (int i = 0; i < 62; i++) {
testField<TProto, T_I64, int64_t>(1L << i);
testField<TProto, T_I64, int64_t>(-(1L << i));
}
testNaked<TProto, double>(123.456);
testNaked<TProto, std::string>("");
testNaked<TProto, std::string>("short");
testNaked<TProto, std::string>("borderlinetiny");
testNaked<TProto, std::string>("a bit longer than the smallest possible");
testNaked<TProto, std::string>("\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA"); //kinda binary test
testField<TProto, T_STRING, std::string>("");
testField<TProto, T_STRING, std::string>("short");
testField<TProto, T_STRING, std::string>("borderlinetiny");
testField<TProto, T_STRING, std::string>("a bit longer than the smallest possible");
testMessage<TProto>();
printf("%s => OK\n", protoname);
} catch (TException e) {
snprintf(errorMessage, ERR_LEN, "%s => Test FAILED: %s", protoname, e.what());
throw TException(errorMessage);
}
}
#endif