You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@thrift.apache.org by Roger Meier <ro...@bufferoverflow.ch> on 2015/07/09 07:14:23 UTC
Re: [3/3] thrift git commit: THRIFT-3221 Create a tool to audit
network compatibility between two .thrift files Client: Compiler (general)
Patch: Sanjay Poojary , Ben Craig
, and Zach Hindes
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 bencraig@apache.org:
> THRIFT-3221 Create a tool to audit network compatibility between two
> .thrift files
> Client: Compiler (general)
> Patch: Sanjay Poojary <sa...@ni.com>, Ben Craig
> <be...@apache.org>, and Zach Hindes <za...@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 <be...@apache.org>
> Authored: Wed Jul 8 20:37:15 2015 -0500
> Committer: Ben Craig <be...@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
> +}
> +
> +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),
> +
> + double 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/break15.thrift
> ----------------------------------------------------------------------
> diff --git a/test/audit/break15.thrift b/test/audit/break15.thrift
> new file mode 100644
> index 0000000..95f69e6
> --- /dev/null
> +++ b/test/audit/break15.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.
> + */
> +
> +// break15 - derived2_function1 return type changed from list<i32>
> to list<i16>
> +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_struct1 derived1_function6(
> + 1: double function6_arg1) throws (1:test_exception2 e),
> +}
> +
> +service derived2 extends base {
> +
> + list<i16> 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/break16.thrift
> ----------------------------------------------------------------------
> diff --git a/test/audit/break16.thrift b/test/audit/break16.thrift
> new file mode 100644
> index 0000000..cdcff7d
> --- /dev/null
> +++ b/test/audit/break16.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.
> + */
> +
> +// break 16 - derived2_function5 return type changed from
> map<test_enum1, test_enum2> to map<test_enum3, test_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_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_enum3, 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/break17.thrift
> ----------------------------------------------------------------------
> diff --git a/test/audit/break17.thrift b/test/audit/break17.thrift
> new file mode 100644
> index 0000000..353b142
> --- /dev/null
> +++ b/test/audit/break17.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.
> + */
> +
> +//break17 - derived2_function6 return type changed from
> map<struct1,struct2> to map<struct1, struct3>
> +
> +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_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_struct3> derived2_function6(
> + 1:bool function6_arg1) throws(1:test_exception2 e),
> +
> +}
Re: [3/3] thrift git commit: THRIFT-3221 Create a tool to audit
network compatibility between two .thrift files Client: Compiler (general)
Patch: Sanjay Poojary , Ben Craig ,
and Zach Hindes
Posted by Ben Craig <be...@gmail.com>.
Moved readme.txt. Python test rewrite is going to need to wait though
(unless you want to take it on). Sorry about that :(
On Thu, Jul 9, 2015 at 8:22 AM, Ben Craig <be...@gmail.com> wrote:
> 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 bencraig@apache.org:
>>
>> THRIFT-3221 Create a tool to audit network compatibility between two
>>> .thrift files
>>> Client: Compiler (general)
>>> Patch: Sanjay Poojary <sa...@ni.com>, Ben Craig
>>> <be...@apache.org>, and Zach Hindes <za...@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 <be...@apache.org>
>>> Authored: Wed Jul 8 20:37:15 2015 -0500
>>> Committer: Ben Craig <be...@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
>>
>>
>
Re: [3/3] thrift git commit: THRIFT-3221 Create a tool to audit
network compatibility between two .thrift files Client: Compiler (general)
Patch: Sanjay Poojary , Ben Craig ,
and Zach Hindes
Posted by Ben Craig <be...@gmail.com>.
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 bencraig@apache.org:
>
> THRIFT-3221 Create a tool to audit network compatibility between two
>> .thrift files
>> Client: Compiler (general)
>> Patch: Sanjay Poojary <sa...@ni.com>, Ben Craig
>> <be...@apache.org>, and Zach Hindes <za...@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 <be...@apache.org>
>> Authored: Wed Jul 8 20:37:15 2015 -0500
>> Committer: Ben Craig <be...@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
>
>