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

Reply via email to