I would prefer python as well. I didn't author the patch though :) I will see about getting the test ported after a couple of weeks. I can take care of copying or moving readme.txt a little sooner.
On Thu, Jul 9, 2015 at 12:14 AM, Roger Meier <ro...@bufferoverflow.ch> wrote: > Hi Ben > > Nice stuff! > Just a few remarks from my side: > - do we really need perl here: test/audit/thrift_audit_test.pl > The cross language test suite is python and I would prefer python here > - I would propose to move compiler/cpp/src/audit/readme.txt to > test/audit/README.md > > Thanks > roger > > > Quoting bencr...@apache.org: > > THRIFT-3221 Create a tool to audit network compatibility between two >> .thrift files >> Client: Compiler (general) >> Patch: Sanjay Poojary <sanjay.pooj...@ni.com>, Ben Craig >> <bencr...@apache.org>, and Zach Hindes <zach.hin...@ni.com> >> >> This closes #541 >> >> >> Project: http://git-wip-us.apache.org/repos/asf/thrift/repo >> Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/262cfb41 >> Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/262cfb41 >> Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/262cfb41 >> >> Branch: refs/heads/master >> Commit: 262cfb4189f3b347f472dfe8b754861ba481c433 >> Parents: 384f976 >> Author: Ben Craig <bencr...@apache.org> >> Authored: Wed Jul 8 20:37:15 2015 -0500 >> Committer: Ben Craig <bencr...@apache.org> >> Committed: Wed Jul 8 20:37:15 2015 -0500 >> >> ---------------------------------------------------------------------- >> compiler/cpp/CMakeLists.txt | 1 + >> compiler/cpp/Makefile.am | 1 + >> compiler/cpp/src/audit/readme.txt | 32 +++ >> compiler/cpp/src/audit/t_audit.cpp | 466 ++++++++++++++++++++++++++++++++ >> compiler/cpp/src/audit/t_audit.h | 11 + >> compiler/cpp/src/main.cc | 199 ++++++++++---- >> compiler/cpp/src/parse/t_program.h | 3 + >> test/audit/break1.thrift | 188 +++++++++++++ >> test/audit/break10.thrift | 190 +++++++++++++ >> test/audit/break11.thrift | 190 +++++++++++++ >> test/audit/break12.thrift | 191 +++++++++++++ >> test/audit/break13.thrift | 191 +++++++++++++ >> test/audit/break14.thrift | 190 +++++++++++++ >> test/audit/break15.thrift | 190 +++++++++++++ >> test/audit/break16.thrift | 191 +++++++++++++ >> test/audit/break17.thrift | 191 +++++++++++++ >> test/audit/break18.thrift | 191 +++++++++++++ >> test/audit/break19.thrift | 191 +++++++++++++ >> test/audit/break2.thrift | 190 +++++++++++++ >> test/audit/break20.thrift | 190 +++++++++++++ >> test/audit/break21.thrift | 190 +++++++++++++ >> test/audit/break22.thrift | 190 +++++++++++++ >> test/audit/break23.thrift | 192 +++++++++++++ >> test/audit/break24.thrift | 191 +++++++++++++ >> test/audit/break25.thrift | 191 +++++++++++++ >> test/audit/break26.thrift | 191 +++++++++++++ >> test/audit/break27.thrift | 190 +++++++++++++ >> test/audit/break28.thrift | 190 +++++++++++++ >> test/audit/break29.thrift | 191 +++++++++++++ >> test/audit/break3.thrift | 191 +++++++++++++ >> test/audit/break30.thrift | 190 +++++++++++++ >> test/audit/break31.thrift | 191 +++++++++++++ >> test/audit/break32.thrift | 191 +++++++++++++ >> test/audit/break33.thrift | 191 +++++++++++++ >> test/audit/break34.thrift | 192 +++++++++++++ >> test/audit/break4.thrift | 190 +++++++++++++ >> test/audit/break5.thrift | 190 +++++++++++++ >> test/audit/break6.thrift | 191 +++++++++++++ >> test/audit/break7.thrift | 190 +++++++++++++ >> test/audit/break8.thrift | 191 +++++++++++++ >> test/audit/break9.thrift | 190 +++++++++++++ >> test/audit/test.thrift | 189 +++++++++++++ >> test/audit/thrift_audit_test.pl | 261 ++++++++++++++++++ >> test/audit/warning.thrift | 190 +++++++++++++ >> 44 files changed, 7785 insertions(+), 46 deletions(-) >> ---------------------------------------------------------------------- >> >> >> >> http://git-wip-us.apache.org/repos/asf/thrift/blob/262cfb41/compiler/cpp/CMakeLists.txt >> ---------------------------------------------------------------------- >> diff --git a/compiler/cpp/CMakeLists.txt b/compiler/cpp/CMakeLists.txt >> index 01e229d..bc6591c 100644 >> --- a/compiler/cpp/CMakeLists.txt >> +++ b/compiler/cpp/CMakeLists.txt >> @@ -56,6 +56,7 @@ set( thrift_SOURCES >> src/main.h >> src/platform.h >> src/md5.h >> + src/audit/t_audit.cpp >> src/parse/t_doc.h >> src/parse/t_type.h >> src/parse/t_base_type.h >> >> >> http://git-wip-us.apache.org/repos/asf/thrift/blob/262cfb41/compiler/cpp/Makefile.am >> ---------------------------------------------------------------------- >> diff --git a/compiler/cpp/Makefile.am b/compiler/cpp/Makefile.am >> index 559a839..f5514d9 100644 >> --- a/compiler/cpp/Makefile.am >> +++ b/compiler/cpp/Makefile.am >> @@ -40,6 +40,7 @@ thrift_SOURCES = src/main.cc \ >> src/platform.h \ >> src/logging.h \ >> src/md5.h \ >> + src/audit/t_audit.cpp \ >> src/parse/t_doc.h \ >> src/parse/t_type.h \ >> src/parse/t_base_type.h \ >> >> >> http://git-wip-us.apache.org/repos/asf/thrift/blob/262cfb41/compiler/cpp/src/audit/readme.txt >> ---------------------------------------------------------------------- >> diff --git a/compiler/cpp/src/audit/readme.txt >> b/compiler/cpp/src/audit/readme.txt >> new file mode 100644 >> index 0000000..f1c53e3 >> --- /dev/null >> +++ b/compiler/cpp/src/audit/readme.txt >> @@ -0,0 +1,32 @@ >> +Typical usage: >> + thrift.exe --audit <oldFile> <newFile> >> +Example run: >> + > thrift.exe --audit test.thrift break1.thrift >> + [Thrift Audit Failure:break1.thrift] New Thrift File has missing >> function base_function3 >> + [Thrift Audit Warning:break1.thrift] Constant const3 has different >> value >> + >> +Problems that the audit tool can catch: >> +Errors >> + Removing an enum value >> + Changing the type of a struct field >> + Changing the required-ness of a struct field >> + Removing a struct field >> + Adding a required struct field >> + Adding a struct field 'in the middle'. This usually indicates an >> old ID has been recycled >> + Struct removed >> + Oneway-ness change >> + Return type change >> + Missing function >> + Missing service >> + Change in service inheritance >> +Warnings >> + Removing a language namespace declaration >> + Changing a namespace >> + Changing an enum value's name >> + Removing an enum class >> + Default value changed >> + Struct field name change >> + Removed constant >> + Type of constant changed >> + Value of constant changed >> + >> \ No newline at end of file >> >> >> http://git-wip-us.apache.org/repos/asf/thrift/blob/262cfb41/compiler/cpp/src/audit/t_audit.cpp >> ---------------------------------------------------------------------- >> diff --git a/compiler/cpp/src/audit/t_audit.cpp >> b/compiler/cpp/src/audit/t_audit.cpp >> new file mode 100644 >> index 0000000..afcbd5e >> --- /dev/null >> +++ b/compiler/cpp/src/audit/t_audit.cpp >> @@ -0,0 +1,466 @@ >> + >> +#include <cassert> >> +#include <stdlib.h> >> +#include <stdio.h> >> +#include <stdarg.h> >> +#include <time.h> >> +#include <string> >> +#include <algorithm> >> +#include <sys/types.h> >> +#include <sys/stat.h> >> +#include <errno.h> >> +#include <limits.h> >> + >> +// Careful: must include globals first for extern definitions >> +#include "globals.h" >> + >> +#include "parse/t_program.h" >> +#include "parse/t_scope.h" >> +#include "parse/t_const.h" >> +#include "parse/t_field.h" >> + >> +#include "version.h" >> + >> +#include "t_audit.h" >> + >> +extern int g_warn; >> +extern std::string g_curpath; >> +extern bool g_return_failure; >> + >> +void thrift_audit_warning(int level, const char* fmt, ...) { >> + if (g_warn < level) { >> + return; >> + } >> + va_list args; >> + printf("[Thrift Audit Warning:%s] ", g_curpath.c_str()); >> + va_start(args, fmt); >> + vprintf(fmt, args); >> + va_end(args); >> + printf("\n"); >> +} >> + >> +void thrift_audit_failure(const char* fmt, ...) { >> + va_list args; >> + fprintf(stderr, "[Thrift Audit Failure:%s] ", g_curpath.c_str()); >> + va_start(args, fmt); >> + vfprintf(stderr, fmt, args); >> + va_end(args); >> + fprintf(stderr, "\n"); >> + g_return_failure = true; >> +} >> + >> +void compare_namespace(t_program* newProgram, t_program* oldProgram) >> +{ >> + const std::map<std::string, std::string>& newNamespaceMap = >> newProgram->get_all_namespaces(); >> + const std::map<std::string, std::string>& oldNamespaceMap = >> oldProgram->get_all_namespaces(); >> + >> + for(std::map<std::string, std::string>::const_iterator >> oldNamespaceMapIt = oldNamespaceMap.begin(); >> + oldNamespaceMapIt != oldNamespaceMap.end(); >> + oldNamespaceMapIt++) >> + { >> + std::map<std::string, std::string>::const_iterator >> newNamespaceMapIt = newNamespaceMap.find(oldNamespaceMapIt->first); >> + if(newNamespaceMapIt == newNamespaceMap.end()) >> + { >> + thrift_audit_warning(1, "Language %s not found in new thrift >> file\n", (oldNamespaceMapIt->first).c_str()); >> + } >> + else if((newNamespaceMapIt->second) != oldNamespaceMapIt->second) >> + { >> + thrift_audit_warning(1, "Namespace %s changed in new thrift >> file\n", (oldNamespaceMapIt->second).c_str()); >> + } >> + } >> +} >> + >> +void compare_enum_values(t_enum* newEnum,t_enum* oldEnum) >> +{ >> + const std::vector<t_enum_value*>& oldEnumValues = >> oldEnum->get_constants(); >> + for(std::vector<t_enum_value*>::const_iterator oldEnumValuesIt = >> oldEnumValues.begin(); >> + oldEnumValuesIt != oldEnumValues.end(); >> + oldEnumValuesIt++) >> + { >> + int enumValue = (*oldEnumValuesIt)->get_value(); >> + t_enum_value* newEnumValue = >> newEnum->get_constant_by_value(enumValue); >> + if(newEnumValue != NULL) >> + { >> + std::string enumName = (*oldEnumValuesIt)->get_name(); >> + if(enumName != newEnumValue->get_name()) >> + { >> + thrift_audit_warning(1, "Name of the value %d changed in >> enum %s\n", enumValue, oldEnum->get_name().c_str()); >> + } >> + } >> + else >> + { >> + thrift_audit_failure("Enum value %d missing in %s\n", >> enumValue, oldEnum->get_name().c_str()); >> + } >> + >> + } >> +} >> + >> +void compare_enums(const std::vector<t_enum*>& newEnumList, const >> std::vector<t_enum*>& oldEnumList) >> +{ >> + std::map<std::string,t_enum*> newEnumMap; >> + std::vector<t_enum*>::const_iterator newEnumIt; >> + for(newEnumIt = newEnumList.begin(); newEnumIt != newEnumList.end(); >> newEnumIt++) >> + { >> + newEnumMap[(*newEnumIt)->get_name()] = *newEnumIt; >> + } >> + std::vector<t_enum*>::const_iterator oldEnumIt; >> + for(oldEnumIt = oldEnumList.begin(); oldEnumIt != oldEnumList.end(); >> oldEnumIt++) >> + { >> + std::map<std::string,t_enum*>::iterator newEnumMapIt; >> + newEnumMapIt = newEnumMap.find((*oldEnumIt)->get_name()); >> + >> + if(newEnumMapIt == newEnumMap.end()) >> + { >> + thrift_audit_warning(1, "Enum %s not found in new thrift >> file\n",(*oldEnumIt)->get_name().c_str()); >> + } >> + else >> + { >> + compare_enum_values(newEnumMapIt->second, *oldEnumIt); >> + } >> + } >> +} >> + >> +//This function returns 'true' if the two arguements are of same types. >> +//Returns false if they are of different type >> +bool compare_type(t_type* newType, t_type* oldType) >> +{ >> + //Comparing names of two types will work when the newType and oldType >> are basic types or structs or enums. >> + //However, when they are containers, get_name() returns empty for >> which we have to compare the type of >> + //their elements as well. >> + if((newType->get_name()).empty() && (oldType->get_name()).empty()) >> + { >> + >> + if(newType->is_list() && oldType->is_list()) >> + { >> + t_type* newElementType = ((t_list*)newType)->get_elem_type(); >> + t_type* oldElementType = ((t_list*)oldType)->get_elem_type(); >> + return compare_type(newElementType, oldElementType); >> + } >> + else if(newType->is_map() && oldType->is_map()) >> + { >> + t_type* newKeyType = ((t_map*)newType)->get_key_type(); >> + t_type* oldKeyType = ((t_map*)oldType)->get_key_type(); >> + >> + t_type* newValType = ((t_map*)newType)->get_val_type(); >> + t_type* oldValType = ((t_map*)oldType)->get_val_type(); >> + >> + return (compare_type(newKeyType, oldKeyType) && >> compare_type(newValType, oldValType)); >> + } >> + else if(newType->is_set() && oldType->is_set()) >> + { >> + t_type* newElementType = ((t_set*)newType)->get_elem_type(); >> + t_type* oldElementType = ((t_set*)oldType)->get_elem_type(); >> + return compare_type(newElementType, oldElementType); >> + } >> + else >> + { >> + return false; >> + } >> + } >> + else if(newType->get_name() == oldType->get_name()) >> + { >> + return true; >> + } >> + else >> + { >> + return false; >> + } >> +} >> + >> +bool compare_pair(std::pair<t_const_value*, t_const_value*> newMapPair, >> std::pair<t_const_value*, t_const_value*> oldMapPair) >> +{ >> + return compare_defaults(newMapPair.first, oldMapPair.first) && >> compare_defaults(newMapPair.second, oldMapPair.second); >> +} >> + >> +// This function returns 'true' if the default values are same. Returns >> false if they are different. >> +bool compare_defaults(t_const_value* newStructDefault, t_const_value* >> oldStructDefault) >> +{ >> + if(newStructDefault == NULL && oldStructDefault == NULL) return true; >> + else if(newStructDefault == NULL && oldStructDefault != NULL) return >> false; >> + else if (newStructDefault != NULL && oldStructDefault == NULL) return >> false; >> + >> + if(newStructDefault->get_type() != oldStructDefault->get_type()) >> + { >> + return false; >> + } >> + >> + switch(newStructDefault->get_type()) >> + { >> + case t_const_value::CV_INTEGER: >> + return (newStructDefault->get_integer() == >> oldStructDefault->get_integer()); >> + case t_const_value::CV_DOUBLE: >> + return (newStructDefault->get_double() == >> oldStructDefault->get_double()); >> + case t_const_value::CV_STRING: >> + return (newStructDefault->get_string() == >> oldStructDefault->get_string()); >> + case t_const_value::CV_LIST: >> + { >> + const std::vector<t_const_value*>& oldDefaultList = >> oldStructDefault->get_list(); >> + const std::vector<t_const_value*>& newDefaultList = >> newStructDefault->get_list(); >> + bool defaultValuesCompare = (oldDefaultList.size() == >> newDefaultList.size()); >> + >> + return defaultValuesCompare && >> std::equal(newDefaultList.begin(), newDefaultList.end(), >> oldDefaultList.begin(), compare_defaults); >> + } >> + case t_const_value::CV_MAP: >> + { >> + const std::map<t_const_value*, t_const_value*> newMap = >> newStructDefault->get_map(); >> + const std::map<t_const_value*, t_const_value*> oldMap = >> oldStructDefault->get_map(); >> + >> + bool defaultValuesCompare = (oldMap.size() == newMap.size()); >> + >> + return defaultValuesCompare && std::equal(newMap.begin(), >> newMap.end(), oldMap.begin(), compare_pair); >> + } >> + case t_const_value::CV_IDENTIFIER: >> + return (newStructDefault->get_identifier() == >> oldStructDefault->get_identifier()); >> + default: >> + return false; >> + } >> + >> +} >> + >> +void compare_struct_field(t_field* newField, t_field* oldField, >> std::string oldStructName) >> +{ >> + t_type* newFieldType = newField->get_type(); >> + t_type* oldFieldType = oldField->get_type(); >> + if(!compare_type(newFieldType, oldFieldType)) >> + { >> + thrift_audit_failure("Struct Field Type Changed for Id = %d in %s >> \n", newField->get_key(), oldStructName.c_str()); >> + } >> + >> + // A Struct member can be optional if it is mentioned explicitly, or >> if it is assigned with default values. >> + bool newStructFieldOptional = (newField->get_req() != >> t_field::T_REQUIRED); >> + bool oldStructFieldOptional = (oldField->get_req() != >> t_field::T_REQUIRED); >> + >> + if(newStructFieldOptional != oldStructFieldOptional) >> + { >> + thrift_audit_failure("Struct Field Requiredness Changed for Id = >> %d in %s \n", newField->get_key(), oldStructName.c_str()); >> + } >> + if(newStructFieldOptional || oldStructFieldOptional) >> + { >> + if(!compare_defaults(newField->get_value(), oldField->get_value())) >> + { >> + thrift_audit_warning(1, "Default value changed for Id = %d in >> %s \n", newField->get_key(), oldStructName.c_str()); >> + } >> + } >> + >> + std::string fieldName = newField->get_name(); >> + if(fieldName != oldField->get_name()) >> + { >> + thrift_audit_warning(1, "Struct field name changed for Id = %d in >> %s\n", newField->get_key(), oldStructName.c_str()); >> + } >> + >> +} >> + >> +void compare_single_struct(t_struct* newStruct, t_struct* oldStruct, >> const std::string& oldStructName = std::string()) >> +{ >> + std::string structName = oldStructName.empty() ? >> oldStruct->get_name() : oldStructName; >> + const std::vector<t_field*>& oldStructMembersInIdOrder = >> oldStruct->get_sorted_members(); >> + const std::vector<t_field*>& newStructMembersInIdOrder = >> newStruct->get_sorted_members(); >> + std::vector<t_field*>::const_iterator oldStructMemberIt = >> oldStructMembersInIdOrder.begin(); >> + std::vector<t_field*>::const_iterator newStructMemberIt = >> newStructMembersInIdOrder.begin(); >> + >> + // Since we have the struct members in their ID order, comparing >> their IDs can be done by traversing the two member >> + // lists together. >> + while(!(oldStructMemberIt == oldStructMembersInIdOrder.end() && >> newStructMemberIt == newStructMembersInIdOrder.end())) >> + { >> + if(newStructMemberIt == newStructMembersInIdOrder.end() && >> oldStructMemberIt != oldStructMembersInIdOrder.end()) >> + { >> + // A field ID has been removed from the end. >> + thrift_audit_failure("Struct Field removed for Id = %d in %s >> \n", (*oldStructMemberIt)->get_key(), structName.c_str()); >> + oldStructMemberIt++; >> + } >> + else if(newStructMemberIt != newStructMembersInIdOrder.end() && >> oldStructMemberIt == oldStructMembersInIdOrder.end()) >> + { >> + //New field ID has been added to the end. >> + if((*newStructMemberIt)->get_req() == t_field::T_REQUIRED) >> + { >> + thrift_audit_failure("Required Struct Field Added for Id = >> %d in %s \n", (*newStructMemberIt)->get_key(), structName.c_str()); >> + } >> + newStructMemberIt++; >> + } >> + else if((*newStructMemberIt)->get_key() == >> (*oldStructMemberIt)->get_key()) >> + { >> + //Field ID found in both structs. Compare field types, default >> values. >> + compare_struct_field(*newStructMemberIt, *oldStructMemberIt, >> structName); >> + >> + newStructMemberIt++; >> + oldStructMemberIt++; >> + } >> + else if((*newStructMemberIt)->get_key() < >> (*oldStructMemberIt)->get_key()) >> + { >> + //New Field Id is inserted in between >> + //Adding fields to struct is fine, but adding them in the >> middle is suspicious. Error!! >> + thrift_audit_failure("Struct field is added in the middle with >> Id = %d in %s\n", (*newStructMemberIt)->get_key(), structName.c_str()); >> + newStructMemberIt++; >> + } >> + else if((*newStructMemberIt)->get_key() > >> (*oldStructMemberIt)->get_key()) >> + { >> + //A field is deleted in newStruct. >> + thrift_audit_failure("Struct Field removed for Id = %d in %s >> \n", (*oldStructMemberIt)->get_key(), structName.c_str()); >> + oldStructMemberIt++; >> + } >> + >> + } >> +} >> + >> +void compare_structs(const std::vector<t_struct*>& newStructList, const >> std::vector<t_struct*>& oldStructList) >> +{ >> + std::map<std::string,t_struct*> newStructMap; >> + std::vector<t_struct*>::const_iterator newStructListIt; >> + for(newStructListIt = newStructList.begin(); newStructListIt != >> newStructList.end(); newStructListIt++) >> + { >> + newStructMap[(*newStructListIt)->get_name()] = *newStructListIt; >> + } >> + >> + std::vector<t_struct*>::const_iterator oldStructListIt; >> + for(oldStructListIt = oldStructList.begin(); oldStructListIt != >> oldStructList.end(); oldStructListIt++) >> + { >> + std::map<std::string, t_struct*>::iterator newStructMapIt; >> + newStructMapIt = newStructMap.find((*oldStructListIt)->get_name()); >> + if(newStructMapIt == newStructMap.end()) >> + { >> + thrift_audit_failure("Struct %s not found in new thrift >> file\n", (*oldStructListIt)->get_name().c_str()); >> + } >> + else >> + { >> + compare_single_struct(newStructMapIt->second, *oldStructListIt); >> + } >> + } >> + >> +} >> + >> +void compare_single_function(t_function* newFunction, t_function* >> oldFunction) >> +{ >> + t_type* newFunctionReturnType = newFunction->get_returntype(); >> + >> + if(newFunction->is_oneway() != oldFunction->is_oneway()) >> + { >> + thrift_audit_failure("Oneway attribute changed for function >> %s\n",oldFunction->get_name().c_str()); >> + } >> + if(!compare_type(newFunctionReturnType, >> oldFunction->get_returntype())) >> + { >> + thrift_audit_failure("Return type changed for function >> %s\n",oldFunction->get_name().c_str()); >> + } >> + >> + //Compare function arguments. >> + compare_single_struct(newFunction->get_arglist(), >> oldFunction->get_arglist()); >> + std::string exceptionName = oldFunction->get_name(); >> + exceptionName += "_exception"; >> + compare_single_struct(newFunction->get_xceptions(), >> oldFunction->get_xceptions(), exceptionName); >> +} >> + >> +void compare_functions(const std::vector<t_function*>& newFunctionList, >> const std::vector<t_function*>& oldFunctionList) >> +{ >> + std::map<std::string, t_function*> newFunctionMap; >> + std::map<std::string, t_function*>::iterator newFunctionMapIt; >> + for(std::vector<t_function*>::const_iterator newFunctionIt = >> newFunctionList.begin(); >> + newFunctionIt != newFunctionList.end(); >> + newFunctionIt++) >> + { >> + newFunctionMap[(*newFunctionIt)->get_name()] = *newFunctionIt; >> + } >> + >> + for(std::vector<t_function*>::const_iterator oldFunctionIt = >> oldFunctionList.begin(); >> + oldFunctionIt != oldFunctionList.end(); >> + oldFunctionIt++) >> + { >> + newFunctionMapIt = >> newFunctionMap.find((*oldFunctionIt)->get_name()); >> + if(newFunctionMapIt == newFunctionMap.end()) >> + { >> + thrift_audit_failure("New Thrift File has missing function >> %s\n",(*oldFunctionIt)->get_name().c_str()); >> + continue; >> + } >> + else >> + { >> + //Function is found in both thrift files. Compare return type >> and argument list >> + compare_single_function(newFunctionMapIt->second, >> *oldFunctionIt); >> + } >> + } >> + >> +} >> + >> +void compare_services(const std::vector<t_service*>& newServices, const >> std::vector<t_service*>& oldServices) >> +{ >> + std::vector<t_service*>::const_iterator oldServiceIt; >> + >> + std::map<std::string, t_service*> newServiceMap; >> + for(std::vector<t_service*>::const_iterator newServiceIt = >> newServices.begin(); >> + newServiceIt != newServices.end(); >> + newServiceIt++) >> + { >> + newServiceMap[(*newServiceIt)->get_name()] = *newServiceIt; >> + } >> + >> + >> + for(oldServiceIt = oldServices.begin(); oldServiceIt != >> oldServices.end(); oldServiceIt++) >> + { >> + const std::string oldServiceName = (*oldServiceIt)->get_name(); >> + std::map<std::string, t_service*>::iterator newServiceMapIt = >> newServiceMap.find(oldServiceName); >> + >> + if(newServiceMapIt == newServiceMap.end()) >> + { >> + thrift_audit_failure("New Thrift file is missing a service >> %s\n", oldServiceName.c_str()); >> + } >> + else >> + { >> + t_service* oldServiceExtends = (*oldServiceIt)->get_extends(); >> + t_service* newServiceExtends = >> (newServiceMapIt->second)->get_extends(); >> + >> + if(oldServiceExtends == NULL) >> + { >> + // It is fine to add extends. So if service in older thrift >> did not have any extends, we are fine. >> + // DO Nothing >> + } >> + else if(oldServiceExtends != NULL && newServiceExtends == NULL) >> + { >> + thrift_audit_failure("Change in Service inheritance for >> %s\n", oldServiceName.c_str()); >> + } >> + else >> + { >> + std::string oldExtendsName = oldServiceExtends->get_name(); >> + std::string newExtendsName = newServiceExtends->get_name(); >> + >> + if( newExtendsName != oldExtendsName) >> + { >> + thrift_audit_failure("Change in Service inheritance for >> %s\n", oldServiceName.c_str()); >> + } >> + } >> + >> + compare_functions((newServiceMapIt->second)->get_functions(), >> (*oldServiceIt)->get_functions()); >> + } >> + >> + } >> + >> +} >> + >> +void compare_consts(const std::vector<t_const*>& newConst, const >> std::vector<t_const*>& oldConst) >> +{ >> + std::vector<t_const*>::const_iterator newConstIt; >> + std::vector<t_const*>::const_iterator oldConstIt; >> + >> + std::map<std::string, t_const*> newConstMap; >> + >> + for(newConstIt = newConst.begin(); newConstIt != newConst.end(); >> newConstIt++) >> + { >> + newConstMap[(*newConstIt)->get_name()] = *newConstIt; >> + } >> + >> + std::map<std::string, t_const*>::const_iterator newConstMapIt; >> + for(oldConstIt = oldConst.begin(); oldConstIt != oldConst.end(); >> oldConstIt++) >> + { >> + newConstMapIt = newConstMap.find((*oldConstIt)->get_name()); >> + if(newConstMapIt == newConstMap.end()) >> + { >> + thrift_audit_warning(1, "Constants Missing %s \n", >> ((*oldConstIt)->get_name()).c_str()); >> + } >> + else if(!compare_type((newConstMapIt->second)->get_type(), >> (*oldConstIt)->get_type())) >> + { >> + thrift_audit_warning(1, "Constant %s is of different type \n", >> ((*oldConstIt)->get_name()).c_str()); >> + } >> + else if(!compare_defaults((newConstMapIt->second)->get_value(), >> (*oldConstIt)->get_value())) >> + { >> + thrift_audit_warning(1, "Constant %s has different value\n", >> ((*oldConstIt)->get_name()).c_str()); >> + } >> + } >> +} >> + >> + >> >> >> http://git-wip-us.apache.org/repos/asf/thrift/blob/262cfb41/compiler/cpp/src/audit/t_audit.h >> ---------------------------------------------------------------------- >> diff --git a/compiler/cpp/src/audit/t_audit.h >> b/compiler/cpp/src/audit/t_audit.h >> new file mode 100644 >> index 0000000..fd0013a >> --- /dev/null >> +++ b/compiler/cpp/src/audit/t_audit.h >> @@ -0,0 +1,11 @@ >> +#ifndef T_AUDIT_H >> +#define T_AUDIT_H >> + >> +void compare_namespace(t_program* newProgram, t_program* oldProgram); >> +void compare_enums(const std::vector<t_enum*>& newEnumList, const >> std::vector<t_enum*>& oldEnumList); >> +bool compare_defaults(t_const_value* newStructDefault, t_const_value* >> oldStructDefault); >> +void compare_structs(const std::vector<t_struct*>& newStructList, const >> std::vector<t_struct*>& oldStructList); >> +void compare_services(const std::vector<t_service*>& newServices, const >> std::vector<t_service*>& oldServices); >> +void compare_consts(const std::vector<t_const*>& newConst, const >> std::vector<t_const*>& oldConst); >> + >> +#endif >> >> >> http://git-wip-us.apache.org/repos/asf/thrift/blob/262cfb41/compiler/cpp/src/main.cc >> ---------------------------------------------------------------------- >> diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc >> index 97d523e..a337cc6 100644 >> --- a/compiler/cpp/src/main.cc >> +++ b/compiler/cpp/src/main.cc >> @@ -51,6 +51,7 @@ >> #include "parse/t_program.h" >> #include "parse/t_scope.h" >> #include "generate/t_generator.h" >> +#include "audit/t_audit.h" >> >> #include "version.h" >> >> @@ -169,6 +170,17 @@ int g_allow_64bit_consts = 0; >> bool gen_recurse = false; >> >> /** >> + * Flags to control thrift audit >> + */ >> +bool g_audit = false; >> + >> +/** >> + * Flag to control return status >> + */ >> +bool g_return_failure = false; >> +bool g_audit_fatal = true; >> + >> +/** >> * Win32 doesn't have realpath, so use fallback implementation in that >> case, >> * otherwise this just calls through to realpath >> */ >> @@ -711,6 +723,13 @@ void help() { >> fprintf(stderr, " Keys and values are options passed to >> the generator.\n"); >> fprintf(stderr, " Many options will not require >> values.\n"); >> fprintf(stderr, "\n"); >> + fprintf(stderr, "Options related to audit operation\n"); >> + fprintf(stderr, " --audit OldFile Old Thrift file to be audited >> with 'file'\n"); >> + fprintf(stderr, " -Iold dir Add a directory to the list of >> directories\n"); >> + fprintf(stderr, " searched for include directives for >> old thrift file\n"); >> + fprintf(stderr, " -Inew dir Add a directory to the list of >> directories\n"); >> + fprintf(stderr, " searched for include directives for >> new thrift file\n"); >> + fprintf(stderr, "\n"); >> fprintf(stderr, "Available generators (and options):\n"); >> >> t_generator_registry::gen_map_t gen_map = >> t_generator_registry::get_generator_map(); >> @@ -1029,6 +1048,30 @@ void generate(t_program* program, const >> vector<string>& generator_strings) { >> } >> } >> >> +void audit(t_program* new_program, t_program* old_program, string >> new_thrift_include_path, string old_thrift_include_path) >> +{ >> + vector<string> temp_incl_searchpath = g_incl_searchpath; >> + if(!old_thrift_include_path.empty()) { >> + g_incl_searchpath.push_back(old_thrift_include_path); >> + } >> + >> + parse(old_program, NULL); >> + >> + g_incl_searchpath = temp_incl_searchpath; >> + if(!new_thrift_include_path.empty()) { >> + g_incl_searchpath.push_back(new_thrift_include_path); >> + } >> + >> + parse(new_program, NULL); >> + >> + compare_namespace(new_program, old_program); >> + compare_services(new_program->get_services(), >> old_program->get_services()); >> + compare_enums(new_program->get_enums(), old_program->get_enums()); >> + compare_structs(new_program->get_structs(), >> old_program->get_structs()); >> + compare_structs(new_program->get_xceptions(), >> old_program->get_xceptions()); >> + compare_consts(new_program->get_consts(), old_program->get_consts()); >> +} >> + >> /** >> * Parse it up.. then spit it back out, in pretty much every language. >> Alright >> * not that many languages, but the cool ones that we care about. >> @@ -1049,6 +1092,9 @@ int main(int argc, char** argv) { >> } >> >> vector<string> generator_strings; >> + string old_thrift_include_path; >> + string new_thrift_include_path; >> + string old_input_file; >> >> // Set the current path to a dummy value to make warning messages >> clearer. >> g_curpath = "arguments"; >> @@ -1118,6 +1164,35 @@ int main(int argc, char** argv) { >> #endif >> if (!check_is_directory(out_path.c_str())) >> return -1; >> + } else if (strcmp(arg, "-audit") == 0) { >> + g_audit = true; >> + arg = argv[++i]; >> + if (arg == NULL) { >> + fprintf(stderr, "Missing old thrift file name for audit >> operation\n"); >> + usage(); >> + } >> + char old_thrift_file_rp[THRIFT_PATH_MAX]; >> + >> + if (saferealpath(arg, old_thrift_file_rp) == NULL) { >> + failure("Could not open input file with realpath: %s", arg); >> + } >> + old_input_file = string(old_thrift_file_rp); >> + } else if(strcmp(arg, "-audit-nofatal") == 0){ >> + g_audit_fatal = false; >> + } else if (strcmp(arg, "-Iold") == 0) { >> + arg = argv[++i]; >> + if (arg == NULL) { >> + fprintf(stderr, "Missing Include directory for old thrift >> file\n"); >> + usage(); >> + } >> + old_thrift_include_path = string(arg); >> + } else if (strcmp(arg, "-Inew") == 0) { >> + arg = argv[++i]; >> + if(arg == NULL) { >> + fprintf(stderr, "Missing Include directory for new thrift >> file\n"); >> + usage(); >> + } >> + new_thrift_include_path = string(arg); >> } else { >> fprintf(stderr, "Unrecognized option: %s\n", arg); >> usage(); >> @@ -1139,41 +1214,6 @@ int main(int argc, char** argv) { >> exit(0); >> } >> >> - // You gotta generate something! >> - if (generator_strings.empty()) { >> - fprintf(stderr, "No output language(s) specified\n"); >> - usage(); >> - } >> - >> - // Real-pathify it >> - char rp[THRIFT_PATH_MAX]; >> - if (argv[i] == NULL) { >> - fprintf(stderr, "Missing file name\n"); >> - usage(); >> - } >> - if (saferealpath(argv[i], rp) == NULL) { >> - failure("Could not open input file with realpath: %s", argv[i]); >> - } >> - string input_file(rp); >> - >> - // Instance of the global parse tree >> - t_program* program = new t_program(input_file); >> - if (out_path.size()) { >> - program->set_out_path(out_path, out_path_is_absolute); >> - } >> - >> - // Compute the cpp include prefix. >> - // infer this from the filename passed in >> - string input_filename = argv[i]; >> - string include_prefix; >> - >> - string::size_type last_slash = string::npos; >> - if ((last_slash = input_filename.rfind("/")) != string::npos) { >> - include_prefix = input_filename.substr(0, last_slash); >> - } >> - >> - program->set_include_prefix(include_prefix); >> - >> // Initialize global types >> g_type_void = new t_base_type("void", t_base_type::TYPE_VOID); >> g_type_string = new t_base_type("string", t_base_type::TYPE_STRING); >> @@ -1188,24 +1228,87 @@ int main(int argc, char** argv) { >> g_type_i64 = new t_base_type("i64", t_base_type::TYPE_I64); >> g_type_double = new t_base_type("double", t_base_type::TYPE_DOUBLE); >> >> - // Parse it! >> - parse(program, NULL); >> + if(g_audit) >> + { >> + // Audit operation >> >> - // The current path is not really relevant when we are doing >> generation. >> - // Reset the variable to make warning messages clearer. >> - g_curpath = "generation"; >> - // Reset yylineno for the heck of it. Use 1 instead of 0 because >> - // That is what shows up during argument parsing. >> - yylineno = 1; >> + if (old_input_file.empty()) { >> + fprintf(stderr, "Missing file name of old thrift file for >> audit\n"); >> + usage(); >> + } >> >> - // Generate it! >> - generate(program, generator_strings); >> + char new_thrift_file_rp[THRIFT_PATH_MAX]; >> + if (argv[i] == NULL) { >> + fprintf(stderr, "Missing file name of new thrift file for >> audit\n"); >> + usage(); >> + } >> + if (saferealpath(argv[i], new_thrift_file_rp) == NULL) { >> + failure("Could not open input file with realpath: %s", argv[i]); >> + } >> + string new_input_file(new_thrift_file_rp); >> + >> + t_program new_program(new_input_file); >> + t_program old_program(old_input_file); >> + >> + audit(&new_program, &old_program, new_thrift_include_path, >> old_thrift_include_path); >> + >> + } else { >> + // Generate options >> + >> + // You gotta generate something! >> + if (generator_strings.empty()) { >> + fprintf(stderr, "No output language(s) specified\n"); >> + usage(); >> + } >> + >> + // Real-pathify it >> + char rp[THRIFT_PATH_MAX]; >> + if (argv[i] == NULL) { >> + fprintf(stderr, "Missing file name\n"); >> + usage(); >> + } >> + if (saferealpath(argv[i], rp) == NULL) { >> + failure("Could not open input file with realpath: %s", argv[i]); >> + } >> + string input_file(rp); >> + >> + // Instance of the global parse tree >> + t_program* program = new t_program(input_file); >> + if (out_path.size()) { >> + program->set_out_path(out_path, out_path_is_absolute); >> + } >> + >> + // Compute the cpp include prefix. >> + // infer this from the filename passed in >> + string input_filename = argv[i]; >> + string include_prefix; >> + >> + string::size_type last_slash = string::npos; >> + if ((last_slash = input_filename.rfind("/")) != string::npos) { >> + include_prefix = input_filename.substr(0, last_slash); >> + } >> + >> + program->set_include_prefix(include_prefix); >> + >> + // Parse it! >> + parse(program, NULL); >> + >> + // The current path is not really relevant when we are doing >> generation. >> + // Reset the variable to make warning messages clearer. >> + g_curpath = "generation"; >> + // Reset yylineno for the heck of it. Use 1 instead of 0 because >> + // That is what shows up during argument parsing. >> + yylineno = 1; >> + >> + // Generate it! >> + generate(program, generator_strings); >> + delete program; >> + } >> >> // Clean up. Who am I kidding... this program probably orphans heap >> memory >> // all over the place, but who cares because it is about to exit and >> it is >> // all referenced and used by this wacky parse tree up until now >> anyways. >> >> - delete program; >> delete g_type_void; >> delete g_type_string; >> delete g_type_bool; >> @@ -1216,5 +1319,9 @@ int main(int argc, char** argv) { >> delete g_type_double; >> >> // Finished >> + if (g_return_failure && g_audit_fatal) { >> + exit(2); >> + } >> + // Finished >> return 0; >> } >> >> >> http://git-wip-us.apache.org/repos/asf/thrift/blob/262cfb41/compiler/cpp/src/parse/t_program.h >> ---------------------------------------------------------------------- >> diff --git a/compiler/cpp/src/parse/t_program.h >> b/compiler/cpp/src/parse/t_program.h >> index cfab691..556ee6c 100644 >> --- a/compiler/cpp/src/parse/t_program.h >> +++ b/compiler/cpp/src/parse/t_program.h >> @@ -321,6 +321,9 @@ public: >> return std::string(); >> } >> >> + const std::map<std::string, std::string>& get_all_namespaces(){ >> + return namespaces_; >> + } >> // Language specific namespace / packaging >> >> void add_cpp_include(std::string path) { >> cpp_includes_.push_back(path); } >> >> >> http://git-wip-us.apache.org/repos/asf/thrift/blob/262cfb41/test/audit/break1.thrift >> ---------------------------------------------------------------------- >> diff --git a/test/audit/break1.thrift b/test/audit/break1.thrift >> new file mode 100644 >> index 0000000..f77f672 >> --- /dev/null >> +++ b/test/audit/break1.thrift >> @@ -0,0 +1,188 @@ >> +/* >> + * 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. >> + */ >> + >> +//Thrift Method removed from service base. >> + >> +namespace cpp test >> + >> +//constants >> +const i32 const1 = 123; >> +const double const2 = 23.3; >> +const map<string,string> const3 = {"hello":"world", "thrift":"audit"}; >> + >> +//Exception >> +exception test_exception1 { >> + 1: i32 code; >> + 2: string json; >> +} >> +exception test_exception2 { >> + 1: i32 code; >> + 2: string json; >> +} >> + >> +//Enums >> + >> +enum test_enum1 { >> + enum1_value0 = 0, >> + enum1_value1 = 1, >> + enum1_value2 = 2, >> + enum1_value5 = 5, >> + enum1_value7 = 7, >> + enum1_value8 = 8 >> +} >> + >> +enum test_enum2 { >> + enum2_value0 = 0, >> + enum2_value1 = 1, >> + enum2_value2 = 2, >> + enum2_value3 = 3 >> +} >> + >> +enum test_enum3 { >> + enum3_value1 = 0, >> + enum3_value2 = 1 >> +} >> + >> +struct test_struct1 { >> + 1: i16 struct1_member1, >> + 2: i32 struct1_member2, >> + 3: i64 struct1_member3, >> + 4: double struct1_member4 = 2.5, >> + 5: string struct1_member5 = "Audit test", >> + 6: bool struct1_member6, >> + 7: byte struct1_member7, >> + 8: binary struct1_member8, >> + 9: test_enum1 struct1_member9 >> +} >> + >> +struct test_struct2 { >> + 1: list<i16> struct2_member1, >> + 2: list<i32> struct2_member2, >> + 3: list<i64> struct2_member3= [23, 32], >> + 4: list<double> struct2_member4, >> + 5: list<string> struct2_member5, >> + 6: list<bool> struct2_member6, >> + 7: list<byte> struct2_member7, >> + 8: list<binary> struct2_member8, >> + 9: list<test_enum1> struct2_member9 >> +} >> + >> +struct test_struct3 { >> + 1: map<i16, i32> struct3_member1 = {1:2, 3:4}, >> + 2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1}, >> + 3: map<string, bool> struct3_member3, >> + 4: map<byte, test_enum1> struct3_member4, >> + 5: map<test_enum2, test_enum3 > struct3_member5, >> + 7: map<double, string> struct3_member7 >> +} >> + >> +struct test_struct4 { >> + 1: i32 struct4_member1, >> + 2: optional i32 struct4_member2 >> +} >> + >> +struct test_struct5{ >> + 1: double struct5_member1, >> + 2: string struct5_member2 = "Thrift Audit Test" >> +} >> +struct test_struct6 { >> + 1: i32 struct6_member1, >> + 2: required i32 struct6_member2 >> +} >> + >> +service base { >> + oneway void base_oneway( >> + 1: i32 arg1), >> + >> + void base_function1( >> + 1: i16 function1_arg1, >> + 2: i32 function1_arg2, >> + 3: i64 function1_arg3, >> + 4: double function1_arg4, >> + 5: string function1_arg5, >> + 6: bool function1_arg6, >> + 7: test_enum1 function1_arg7, >> + 8: test_struct1 function1_arg8), >> + >> + void base_function2( >> + 1: list<i16> function2_arg1, >> + 2: list<i32> function2_arg2, >> + 3: list<i64> function2_arg3, >> + 4: list<double> function2_arg4, >> + 5: list<string> function2_arg5, >> + 6: list<bool> function2_arg6, >> + 7: list<byte> function2_arg7, >> + 8: list<test_enum1> function2_arg8, >> + 9: list<test_struct1> function2_arg9) throws (1:test_exception2 >> e), >> + >> +} >> + >> +service derived1 extends base { >> + >> + test_enum1 derived1_function1( >> + 1: i64 function1_arg1, >> + 2: double function1_arg2, >> + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), >> + >> + i64 derived1_function2( >> + 1: list<i64> function2_arg1, >> + 2: list<double> function2_arg2, >> + 3: list<string> function2_arg3, >> + 4: list<byte> function2_arg4, >> + 5: list<test_enum1> function2_arg5) throws (1:test_exception2 e), >> + >> + double derived1_function3( >> + 1: string function3_arg1, >> + 2: bool function3_arg2) throws (1:test_exception2 e), >> + >> + string derived1_function4( >> + 1: string function4_arg1, >> + 2: bool function4_arg2) throws (1:test_exception2 e), >> + >> + >> + bool derived1_function5( >> + 1: map<i64, double> function5_arg1, >> + 2: map<string, bool> function5_arg2, >> + 3: map<test_enum1, test_enum2> function5_arg3) throws >> (1:test_exception2 e), >> + >> + test_struct1 derived1_function6( >> + 1: double function6_arg1) throws (1:test_exception2 e), >> +} >> + >> +service derived2 extends base { >> + >> + list<i32> derived2_function1( >> + 1: i32 function1_arg1) throws (1:test_exception2 e), >> + >> + list<test_enum1> derived2_function2( >> + 1:i64 function2_arg2) throws (1:test_exception2 e), >> + >> + list<test_struct1> derived2_function3( >> + 1:double function3_arg1) throws(1:test_exception2 e), >> + >> + map<double, string> derived2_function4( >> + 1:string function4_arg1) throws(1:test_exception2 e), >> + >> + map<test_enum1, test_enum2> derived2_function5( >> + 1:bool function5_arg1) throws(1:test_exception2 e), >> + >> + map<test_struct1, test_struct2> derived2_function6( >> + 1:bool function6_arg1) throws(1:test_exception2 e), >> + >> +} >> >> >> http://git-wip-us.apache.org/repos/asf/thrift/blob/262cfb41/test/audit/break10.thrift >> ---------------------------------------------------------------------- >> diff --git a/test/audit/break10.thrift b/test/audit/break10.thrift >> new file mode 100644 >> index 0000000..00690aa >> --- /dev/null >> +++ b/test/audit/break10.thrift >> @@ -0,0 +1,190 @@ >> +/* >> + * 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. >> + */ >> + >> +//break10 - Struct field removed from struct2 id =1 >> + >> +namespace cpp test >> + >> +//Constants >> +const i32 const1 = 123; >> +const double const2 = 23.3; >> +const map<string,string> const3 = {"hello":"world", "thrift":"audit"}; >> + >> + >> +//Exception >> +exception test_exception1 { >> + 1: i32 code; >> + 2: string json; >> +} >> +exception test_exception2 { >> + 1: i32 code; >> + 2: string json; >> +} >> + >> +//Enums >> + >> +enum test_enum1 { >> + enum1_value0 = 0, >> + enum1_value1 = 1, >> + enum1_value2 = 2, >> + enum1_value5 = 5, >> + enum1_value7 = 7, >> + enum1_value8 = 8 >> +} >> + >> +enum test_enum2 { >> + enum2_value0 = 0, >> + enum2_value1 = 1, >> + enum2_value2 = 2, >> + enum2_value3 = 3 >> +} >> + >> +enum test_enum3 { >> + enum3_value1 = 0, >> + enum3_value2 = 1 >> +} >> + >> +struct test_struct1 { >> + 1: i16 struct1_member1, >> + 2: i32 struct1_member2, >> + 3: i64 struct1_member3, >> + 4: double struct1_member4 = 2.5, >> + 5: string struct1_member5 = "Audit test", >> + 6: bool struct1_member6, >> + 7: byte struct1_member7, >> + 8: binary struct1_member8, >> + 9: test_enum1 struct1_member9 >> +} >> + >> +struct test_struct2 { >> + 2: list<i32> struct2_member2, >> + 3: list<i64> struct2_member3 = [23, 32], >> + 4: list<double> struct2_member4, >> + 5: list<string> struct2_member5, >> + 6: list<bool> struct2_member6, >> + 7: list<byte> struct2_member7, >> + 8: list<binary> struct2_member8, >> + 9: list<test_enum1> struct2_member9 >> +} >> + >> +struct test_struct3 { >> + 1: map<i16, i32> struct3_member1 = {1:2, 3:4}, >> + 2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1}, >> + 3: map<string, bool> struct3_member3, >> + 4: map<byte, test_enum1> struct3_member4, >> + 5: map<test_enum2, test_enum3 > struct3_member5, >> + 7: map<double, string> struct3_member7 >> +} >> + >> +struct test_struct4 { >> + 1: i32 struct4_member1, >> + 2: optional i32 struct4_member2 >> +} >> + >> +struct test_struct5{ >> + 1: double struct5_member1, >> + 2: string struct5_member2 = "Thrift Audit Test" >> +} >> +struct test_struct6 { >> + 1: i32 struct6_member1, >> + 2: required i32 struct6_member2 >> +} >> + >> +service base { >> + oneway void base_oneway( >> + 1: i32 arg1), >> + >> + void base_function1( >> + 1: i16 function1_arg1, >> + 2: i32 function1_arg2, >> + 3: i64 function1_arg3, >> + 4: double function1_arg4, >> + 5: string function1_arg5, >> + 6: bool function1_arg6, >> + 7: test_enum1 function1_arg7, >> + 8: test_struct1 function1_arg8), >> + >> + void base_function2( >> + 1: list<i16> function2_arg1, >> + 2: list<i32> function2_arg2, >> + 3: list<i64> function2_arg3, >> + 4: list<double> function2_arg4, >> + 5: list<string> function2_arg5, >> + 6: list<bool> function2_arg6, >> + 7: list<byte> function2_arg7, >> + 8: list<test_enum1> function2_arg8, >> + 9: list<test_struct1> function2_arg9) throws (1:test_exception2 >> e), >> + >> + void base_function3(), >> + >> +} >> + >> +service derived1 extends base { >> + >> + test_enum1 derived1_function1( >> + 1: i64 function1_arg1, >> + 2: double function1_arg2, >> + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), >> + >> + i64 derived1_function2( >> + 1: list<i64> function2_arg1, >> + 2: list<double> function2_arg2, >> + 3: list<string> function2_arg3, >> + 4: list<byte> function2_arg4, >> + 5: list<test_enum1> function2_arg5) throws (1:test_exception2 e), >> + >> + double derived1_function3( >> + 1: string function3_arg1, >> + 2: bool function3_arg2) throws (1:test_exception2 e), >> + >> + string derived1_function4( >> + 1: string function4_arg1, >> + 2: bool function4_arg2) throws (1:test_exception2 e), >> + >> + >> + bool derived1_function5( >> + 1: map<i64, double> function5_arg1, >> + 2: map<string, bool> function5_arg2, >> + 3: map<test_enum1, test_enum2> function5_arg3) throws >> (1:test_exception2 e), >> + >> + test_struct1 derived1_function6( >> + 1: double function6_arg1) throws (1:test_exception2 e), >> +} >> + >> +service derived2 extends base { >> + >> + list<i32> derived2_function1( >> + 1: i32 function1_arg1) throws (1:test_exception2 e), >> + >> + list<test_enum1> derived2_function2( >> + 1:i64 function2_arg2) throws (1:test_exception2 e), >> + >> + list<test_struct1> derived2_function3( >> + 1:double function3_arg1) throws(1:test_exception2 e), >> + >> + map<double, string> derived2_function4( >> + 1:string function4_arg1) throws(1:test_exception2 e), >> + >> + map<test_enum1, test_enum2> derived2_function5( >> + 1:bool function5_arg1) throws(1:test_exception2 e), >> + >> + map<test_struct1, test_struct2> derived2_function6( >> + 1:bool function6_arg1) throws(1:test_exception2 e), >> + >> +} >> >> >> http://git-wip-us.apache.org/repos/asf/thrift/blob/262cfb41/test/audit/break11.thrift >> ---------------------------------------------------------------------- >> diff --git a/test/audit/break11.thrift b/test/audit/break11.thrift >> new file mode 100644 >> index 0000000..a4e0a7d >> --- /dev/null >> +++ b/test/audit/break11.thrift >> @@ -0,0 +1,190 @@ >> +/* >> + * 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. >> + */ >> + >> +//break11 - Struct field removed from struct3 id =7 >> + >> +namespace cpp test >> + >> +//Constants >> +const i32 const1 = 123; >> +const double const2 = 23.3; >> +const map<string,string> const3 = {"hello":"world", "thrift":"audit"}; >> + >> + >> +//Exception >> +exception test_exception1 { >> + 1: i32 code; >> + 2: string json; >> +} >> +exception test_exception2 { >> + 1: i32 code; >> + 2: string json; >> +} >> + >> +//Enums >> + >> +enum test_enum1 { >> + enum1_value0 = 0, >> + enum1_value1 = 1, >> + enum1_value2 = 2, >> + enum1_value5 = 5, >> + enum1_value7 = 7, >> + enum1_value8 = 8 >> +} >> + >> +enum test_enum2 { >> + enum2_value0 = 0, >> + enum2_value1 = 1, >> + enum2_value2 = 2, >> + enum2_value3 = 3 >> +} >> + >> +enum test_enum3 { >> + enum3_value1 = 0, >> + enum3_value2 = 1 >> +} >> + >> +struct test_struct1 { >> + 1: i16 struct1_member1, >> + 2: i32 struct1_member2, >> + 3: i64 struct1_member3, >> + 4: double struct1_member4 = 2.5, >> + 5: string struct1_member5 = "Audit test", >> + 6: bool struct1_member6, >> + 7: byte struct1_member7, >> + 8: binary struct1_member8, >> + 9: test_enum1 struct1_member9 >> +} >> + >> +struct test_struct2 { >> + 1: list<i16> struct2_member1, >> + 2: list<i32> struct2_member2, >> + 3: list<i64> struct2_member3 = [23, 32 ], >> + 4: list<double> struct2_member4, >> + 5: list<string> struct2_member5, >> + 6: list<bool> struct2_member6, >> + 7: list<byte> struct2_member7, >> + 8: list<binary> struct2_member8, >> + 9: list<test_enum1> struct2_member9 >> +} >> + >> +struct test_struct3 { >> + 1: map<i16, i32> struct3_member1 = {1:2, 3:4}, >> + 2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1}, >> + 3: map<string, bool> struct3_member3, >> + 4: map<byte, test_enum1> struct3_member4, >> + 5: map<test_enum2, test_enum3 > struct3_member5, >> +} >> + >> +struct test_struct4 { >> + 1: i32 struct4_member1, >> + 2: optional i32 struct4_member2 >> +} >> + >> +struct test_struct5{ >> + 1: double struct5_member1, >> + 2: string struct5_member2 = "Thrift Audit Test" >> +} >> +struct test_struct6 { >> + 1: i32 struct6_member1, >> + 2: required i32 struct6_member2 >> +} >> + >> +service base { >> + oneway void base_oneway( >> + 1: i32 arg1), >> + >> + void base_function1( >> + 1: i16 function1_arg1, >> + 2: i32 function1_arg2, >> + 3: i64 function1_arg3, >> + 4: double function1_arg4, >> + 5: string function1_arg5, >> + 6: bool function1_arg6, >> + 7: test_enum1 function1_arg7, >> + 8: test_struct1 function1_arg8), >> + >> + void base_function2( >> + 1: list<i16> function2_arg1, >> + 2: list<i32> function2_arg2, >> + 3: list<i64> function2_arg3, >> + 4: list<double> function2_arg4, >> + 5: list<string> function2_arg5, >> + 6: list<bool> function2_arg6, >> + 7: list<byte> function2_arg7, >> + 8: list<test_enum1> function2_arg8, >> + 9: list<test_struct1> function2_arg9) throws (1:test_exception2 >> e), >> + >> + void base_function3(), >> + >> +} >> + >> +service derived1 extends base { >> + >> + test_enum1 derived1_function1( >> + 1: i64 function1_arg1, >> + 2: double function1_arg2, >> + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), >> + >> + i64 derived1_function2( >> + 1: list<i64> function2_arg1, >> + 2: list<double> function2_arg2, >> + 3: list<string> function2_arg3, >> + 4: list<byte> function2_arg4, >> + 5: list<test_enum1> function2_arg5) throws (1:test_exception2 e), >> + >> + double derived1_function3( >> + 1: string function3_arg1, >> + 2: bool function3_arg2) throws (1:test_exception2 e), >> + >> + string derived1_function4( >> + 1: string function4_arg1, >> + 2: bool function4_arg2) throws (1:test_exception2 e), >> + >> + >> + bool derived1_function5( >> + 1: map<i64, double> function5_arg1, >> + 2: map<string, bool> function5_arg2, >> + 3: map<test_enum1, test_enum2> function5_arg3) throws >> (1:test_exception2 e), >> + >> + test_struct1 derived1_function6( >> + 1: double function6_arg1) throws (1:test_exception2 e), >> +} >> + >> +service derived2 extends base { >> + >> + list<i32> derived2_function1( >> + 1: i32 function1_arg1) throws (1:test_exception2 e), >> + >> + list<test_enum1> derived2_function2( >> + 1:i64 function2_arg2) throws (1:test_exception2 e), >> + >> + list<test_struct1> derived2_function3( >> + 1:double function3_arg1) throws(1:test_exception2 e), >> + >> + map<double, string> derived2_function4( >> + 1:string function4_arg1) throws(1:test_exception2 e), >> + >> + map<test_enum1, test_enum2> derived2_function5( >> + 1:bool function5_arg1) throws(1:test_exception2 e), >> + >> + map<test_struct1, test_struct2> derived2_function6( >> + 1:bool function6_arg1) throws(1:test_exception2 e), >> + >> +} >> >> >> http://git-wip-us.apache.org/repos/asf/thrift/blob/262cfb41/test/audit/break12.thrift >> ---------------------------------------------------------------------- >> diff --git a/test/audit/break12.thrift b/test/audit/break12.thrift >> new file mode 100644 >> index 0000000..e5522ed >> --- /dev/null >> +++ b/test/audit/break12.thrift >> @@ -0,0 +1,191 @@ >> +/* >> + * 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. >> + */ >> + >> +// derived1_function1 return type changed from enum1 to enum2 >> + >> +namespace cpp test >> + >> +//Constants >> +const i32 const1 = 123; >> +const double const2 = 23.3; >> +const map<string,string> const3 = {"hello":"world", "thrift":"audit"}; >> + >> + >> +//Exception >> +exception test_exception1 { >> + 1: i32 code; >> + 2: string json; >> +} >> +exception test_exception2 { >> + 1: i32 code; >> + 2: string json; >> +} >> + >> +//Enums >> + >> +enum test_enum1 { >> + enum1_value0 = 0, >> + enum1_value1 = 1, >> + enum1_value2 = 2, >> + enum1_value5 = 5, >> + enum1_value7 = 7, >> + enum1_value8 = 8 >> +} >> + >> +enum test_enum2 { >> + enum2_value0 = 0, >> + enum2_value1 = 1, >> + enum2_value2 = 2, >> + enum2_value3 = 3 >> +} >> + >> +enum test_enum3 { >> + enum3_value1 = 0, >> + enum3_value2 = 1 >> +} >> + >> +struct test_struct1 { >> + 1: i16 struct1_member1, >> + 2: i32 struct1_member2, >> + 3: i64 struct1_member3, >> + 4: double struct1_member4 = 2.5, >> + 5: string struct1_member5 = "Audit test", >> + 6: bool struct1_member6, >> + 7: byte struct1_member7, >> + 8: binary struct1_member8, >> + 9: test_enum1 struct1_member9 >> +} >> + >> +struct test_struct2 { >> + 1: list<i16> struct2_member1, >> + 2: list<i32> struct2_member2, >> + 3: list<i64> struct2_member3 = [23, 32 ], >> + 4: list<double> struct2_member4, >> + 5: list<string> struct2_member5, >> + 6: list<bool> struct2_member6, >> + 7: list<byte> struct2_member7, >> + 8: list<binary> struct2_member8, >> + 9: list<test_enum1> struct2_member9 >> +} >> + >> +struct test_struct3 { >> + 1: map<i16, i32> struct3_member1 = {1:2, 3:4}, >> + 2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1}, >> + 3: map<string, bool> struct3_member3, >> + 4: map<byte, test_enum1> struct3_member4, >> + 5: map<test_enum2, test_enum3 > struct3_member5, >> + 7: map<double, string> struct3_member7 >> +} >> + >> +struct test_struct4 { >> + 1: i32 struct4_member1, >> + 2: optional i32 struct4_member2 >> +} >> + >> +struct test_struct5{ >> + 1: double struct5_member1, >> + 2: string struct5_member2 = "Thrift Audit Test" >> +} >> +struct test_struct6 { >> + 1: i32 struct6_member1, >> + 2: required i32 struct6_member2 >> +} >> + >> +service base { >> + oneway void base_oneway( >> + 1: i32 arg1), >> + >> + void base_function1( >> + 1: i16 function1_arg1, >> + 2: i32 function1_arg2, >> + 3: i64 function1_arg3, >> + 4: double function1_arg4, >> + 5: string function1_arg5, >> + 6: bool function1_arg6, >> + 7: test_enum1 function1_arg7, >> + 8: test_struct1 function1_arg8), >> + >> + void base_function2( >> + 1: list<i16> function2_arg1, >> + 2: list<i32> function2_arg2, >> + 3: list<i64> function2_arg3, >> + 4: list<double> function2_arg4, >> + 5: list<string> function2_arg5, >> + 6: list<bool> function2_arg6, >> + 7: list<byte> function2_arg7, >> + 8: list<test_enum1> function2_arg8, >> + 9: list<test_struct1> function2_arg9) throws (1:test_exception2 >> e), >> + >> + void base_function3(), >> + >> +} >> + >> +service derived1 extends base { >> + >> + test_enum2 derived1_function1( >> + 1: i64 function1_arg1, >> + 2: double function1_arg2, >> + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), >> + >> + i64 derived1_function2( >> + 1: list<i64> function2_arg1, >> + 2: list<double> function2_arg2, >> + 3: list<string> function2_arg3, >> + 4: list<byte> function2_arg4, >> + 5: list<test_enum1> function2_arg5) throws (1:test_exception2 e), >> + >> + double derived1_function3( >> + 1: string function3_arg1, >> + 2: bool function3_arg2) throws (1:test_exception2 e), >> + >> + string derived1_function4( >> + 1: string function4_arg1, >> + 2: bool function4_arg2) throws (1:test_exception2 e), >> + >> + >> + bool derived1_function5( >> + 1: map<i64, double> function5_arg1, >> + 2: map<string, bool> function5_arg2, >> + 3: map<test_enum1, test_enum2> function5_arg3) throws >> (1:test_exception2 e), >> + >> + test_struct1 derived1_function6( >> + 1: double function6_arg1) throws (1:test_exception2 e), >> +} >> + >> +service derived2 extends base { >> + >> + list<i32> derived2_function1( >> + 1: i32 function1_arg1) throws (1:test_exception2 e), >> + >> + list<test_enum1> derived2_function2( >> + 1:i64 function2_arg2) throws (1:test_exception2 e), >> + >> + list<test_struct1> derived2_function3( >> + 1:double function3_arg1) throws(1:test_exception2 e), >> + >> + map<double, string> derived2_function4( >> + 1:string function4_arg1) throws(1:test_exception2 e), >> + >> + map<test_enum1, test_enum2> derived2_function5( >> + 1:bool function5_arg1) throws(1:test_exception2 e), >> + >> + map<test_struct1, test_struct2> derived2_function6( >> + 1:bool function6_arg1) throws(1:test_exception2 e), >> + >> +} >> >> >> http://git-wip-us.apache.org/repos/asf/thrift/blob/262cfb41/test/audit/break13.thrift >> ---------------------------------------------------------------------- >> diff --git a/test/audit/break13.thrift b/test/audit/break13.thrift >> new file mode 100644 >> index 0000000..66975cd >> --- /dev/null >> +++ b/test/audit/break13.thrift >> @@ -0,0 +1,191 @@ >> +/* >> + * 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. >> + */ >> + >> +// derived1_function6 return type changed from struct1 to struct2 >> + >> +namespace cpp test >> + >> +//Constants >> +const i32 const1 = 123; >> +const double const2 = 23.3; >> +const map<string,string> const3 = {"hello":"world", "thrift":"audit"}; >> + >> + >> +//Exception >> +exception test_exception1 { >> + 1: i32 code; >> + 2: string json; >> +} >> +exception test_exception2 { >> + 1: i32 code; >> + 2: string json; >> +} >> + >> +//Enums >> + >> +enum test_enum1 { >> + enum1_value0 = 0, >> + enum1_value1 = 1, >> + enum1_value2 = 2, >> + enum1_value5 = 5, >> + enum1_value7 = 7, >> + enum1_value8 = 8 >> +} >> + >> +enum test_enum2 { >> + enum2_value0 = 0, >> + enum2_value1 = 1, >> + enum2_value2 = 2, >> + enum2_value3 = 3 >> +} >> + >> +enum test_enum3 { >> + enum3_value1 = 0, >> + enum3_value2 = 1 >> +} >> + >> +struct test_struct1 { >> + 1: i16 struct1_member1, >> + 2: i32 struct1_member2, >> + 3: i64 struct1_member3, >> + 4: double struct1_member4 = 2.5, >> + 5: string struct1_member5 = "Audit test", >> + 6: bool struct1_member6, >> + 7: byte struct1_member7, >> + 8: binary struct1_member8, >> + 9: test_enum1 struct1_member9 >> +} >> + >> +struct test_struct2 { >> + 1: list<i16> struct2_member1, >> + 2: list<i32> struct2_member2, >> + 3: list<i64> struct2_member3 = [23, 32 ], >> + 4: list<double> struct2_member4, >> + 5: list<string> struct2_member5, >> + 6: list<bool> struct2_member6, >> + 7: list<byte> struct2_member7, >> + 8: list<binary> struct2_member8, >> + 9: list<test_enum1> struct2_member9 >> +} >> + >> +struct test_struct3 { >> + 1: map<i16, i32> struct3_member1 = {1:2, 3:4}, >> + 2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1}, >> + 3: map<string, bool> struct3_member3, >> + 4: map<byte, test_enum1> struct3_member4, >> + 5: map<test_enum2, test_enum3 > struct3_member5, >> + 7: map<double, string> struct3_member7 >> +} >> + >> +struct test_struct4 { >> + 1: i32 struct4_member1, >> + 2: optional i32 struct4_member2 >> +} >> + >> +struct test_struct5{ >> + 1: double struct5_member1, >> + 2: string struct5_member2 = "Thrift Audit Test" >> +} >> +struct test_struct6 { >> + 1: i32 struct6_member1, >> + 2: required i32 struct6_member2 >> +} >> + >> +service base { >> + oneway void base_oneway( >> + 1: i32 arg1), >> + >> + void base_function1( >> + 1: i16 function1_arg1, >> + 2: i32 function1_arg2, >> + 3: i64 function1_arg3, >> + 4: double function1_arg4, >> + 5: string function1_arg5, >> + 6: bool function1_arg6, >> + 7: test_enum1 function1_arg7, >> + 8: test_struct1 function1_arg8), >> + >> + void base_function2( >> + 1: list<i16> function2_arg1, >> + 2: list<i32> function2_arg2, >> + 3: list<i64> function2_arg3, >> + 4: list<double> function2_arg4, >> + 5: list<string> function2_arg5, >> + 6: list<bool> function2_arg6, >> + 7: list<byte> function2_arg7, >> + 8: list<test_enum1> function2_arg8, >> + 9: list<test_struct1> function2_arg9) throws (1:test_exception2 >> e), >> + >> + void base_function3(), >> + >> +} >> + >> +service derived1 extends base { >> + >> + test_enum1 derived1_function1( >> + 1: i64 function1_arg1, >> + 2: double function1_arg2, >> + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), >> + >> + i64 derived1_function2( >> + 1: list<i64> function2_arg1, >> + 2: list<double> function2_arg2, >> + 3: list<string> function2_arg3, >> + 4: list<byte> function2_arg4, >> + 5: list<test_enum1> function2_arg5) throws (1:test_exception2 e), >> + >> + double derived1_function3( >> + 1: string function3_arg1, >> + 2: bool function3_arg2) throws (1:test_exception2 e), >> + >> + string derived1_function4( >> + 1: string function4_arg1, >> + 2: bool function4_arg2) throws (1:test_exception2 e), >> + >> + >> + bool derived1_function5( >> + 1: map<i64, double> function5_arg1, >> + 2: map<string, bool> function5_arg2, >> + 3: map<test_enum1, test_enum2> function5_arg3) throws >> (1:test_exception2 e), >> + >> + test_struct2 derived1_function6( >> + 1: double function6_arg1) throws (1:test_exception2 e), >> +} >> + >> +service derived2 extends base { >> + >> + list<i32> derived2_function1( >> + 1: i32 function1_arg1) throws (1:test_exception2 e), >> + >> + list<test_enum1> derived2_function2( >> + 1:i64 function2_arg2) throws (1:test_exception2 e), >> + >> + list<test_struct1> derived2_function3( >> + 1:double function3_arg1) throws(1:test_exception2 e), >> + >> + map<double, string> derived2_function4( >> + 1:string function4_arg1) throws(1:test_exception2 e), >> + >> + map<test_enum1, test_enum2> derived2_function5( >> + 1:bool function5_arg1) throws(1:test_exception2 e), >> + >> + map<test_struct1, test_struct2> derived2_function6( >> + 1:bool function6_arg1) throws(1:test_exception2 e), >> + >> +} >> >> >> http://git-wip-us.apache.org/repos/asf/thrift/blob/262cfb41/test/audit/break14.thrift >> ---------------------------------------------------------------------- >> diff --git a/test/audit/break14.thrift b/test/audit/break14.thrift >> new file mode 100644 >> index 0000000..4ccd503 >> --- /dev/null >> +++ b/test/audit/break14.thrift >> @@ -0,0 +1,190 @@ >> +/* >> + * 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. >> + */ >> + >> +// derived1_function6 return type changed from string to double >> + >> +namespace cpp test >> +//Constants >> +const i32 const1 = 123; >> +const double const2 = 23.3; >> +const map<string,string> const3 = {"hello":"world", "thrift":"audit"}; >> + >> + >> +//Exception >> +exception test_exception1 { >> + 1: i32 code; >> + 2: string json; >> +} >> +exception test_exception2 { >> + 1: i32 code; >> + 2: string json; >> +} >> + >> +//Enums >> + >> +enum test_enum1 { >> + enum1_value0 = 0, >> + enum1_value1 = 1, >> + enum1_value2 = 2, >> + enum1_value5 = 5, >> + enum1_value7 = 7, >> + enum1_value8 = 8 >> +} >> + >> +enum test_enum2 { >> + enum2_value0 = 0, >> + enum2_value1 = 1, >> + enum2_value2 = 2, >> + enum2_value3 = 3 >> +} >> + >> +enum test_enum3 { >> + enum3_value1 = 0, >> + enum3_value2 = 1 >> +} >> + >> +struct test_struct1 { >> + 1: i16 struct1_member1, >> + 2: i32 struct1_member2, >> + 3: i64 struct1_member3, >> + 4: double struct1_member4 = 2.5, >> + 5: string struct1_member5 = "Audit test", >> + 6: bool struct1_member6, >> + 7: byte struct1_member7, >> + 8: binary struct1_member8, >> + 9: test_enum1 struct1_member9 >> +} >> + >> +struct test_struct2 { >> + 1: list<i16> struct2_member1, >> + 2: list<i32> struct2_member2, >> + 3: list<i64> struct2_member3 = [23, 32 ], >> + 4: list<double> struct2_member4, >> + 5: list<string> struct2_member5, >> + 6: list<bool> struct2_member6, >> + 7: list<byte> struct2_member7, >> + 8: list<binary> struct2_member8, >> + 9: list<test_enum1> struct2_member9 > >