Googletest export
Remove scripts for code generating together with related files. PiperOrigin-RevId: 352805926
This commit is contained in:
parent
997c36c188
commit
59dea67b81
@ -128,15 +128,3 @@ To run the tests, do
|
||||
make test
|
||||
|
||||
All tests should pass.
|
||||
|
||||
### Regenerating Source Files
|
||||
|
||||
Some of Google Test's source files are generated from templates (not in the C++
|
||||
sense) using a script. For example, the file
|
||||
*googlemock/include/gmock/gmock-generated-actions.h.pump* is used to generate
|
||||
*gmock-generated-actions.h* in the same directory.
|
||||
|
||||
You don't need to worry about regenerating the source files unless you need to
|
||||
modify them. You would then modify the corresponding `.pump` files and run the
|
||||
'[pump.py](googlemock/scripts/pump.py)' generator script. See the
|
||||
[Pump Manual](googlemock/docs/pump_manual.md).
|
||||
|
@ -1,190 +0,0 @@
|
||||
<b>P</b>ump is <b>U</b>seful for <b>M</b>eta <b>P</b>rogramming.
|
||||
|
||||
[TOC]
|
||||
|
||||
# The Problem
|
||||
|
||||
Template and macro libraries often need to define many classes, functions, or
|
||||
macros that vary only (or almost only) in the number of arguments they take.
|
||||
It's a lot of repetitive, mechanical, and error-prone work.
|
||||
|
||||
Our experience is that it's tedious to write custom scripts, which tend to
|
||||
reflect the structure of the generated code poorly and are often hard to read
|
||||
and edit. For example, a small change needed in the generated code may require
|
||||
some non-intuitive, non-trivial changes in the script. This is especially
|
||||
painful when experimenting with the code.
|
||||
|
||||
This script may be useful for generating meta code, for example a series of
|
||||
macros of FOO1, FOO2, etc. Nevertheless, please make it your last resort
|
||||
technique by favouring C++ template metaprogramming or variadic macros.
|
||||
|
||||
# Our Solution
|
||||
|
||||
Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta
|
||||
Programming, or Practical Utility for Meta Programming, whichever you prefer) is
|
||||
a simple meta-programming tool for C++. The idea is that a programmer writes a
|
||||
`foo.pump` file which contains C++ code plus meta code that manipulates the C++
|
||||
code. The meta code can handle iterations over a range, nested iterations, local
|
||||
meta variable definitions, simple arithmetic, and conditional expressions. You
|
||||
can view it as a small Domain-Specific Language. The meta language is designed
|
||||
to be non-intrusive (s.t. it won't confuse Emacs' C++ mode, for example) and
|
||||
concise, making Pump code intuitive and easy to maintain.
|
||||
|
||||
## Highlights
|
||||
|
||||
* The implementation is in a single Python script and thus ultra portable: no
|
||||
build or installation is needed and it works cross platforms.
|
||||
* Pump tries to be smart with respect to
|
||||
[Google's style guide](https://github.com/google/styleguide): it breaks long
|
||||
lines (easy to have when they are generated) at acceptable places to fit
|
||||
within 80 columns and indent the continuation lines correctly.
|
||||
* The format is human-readable and more concise than XML.
|
||||
* The format works relatively well with Emacs' C++ mode.
|
||||
|
||||
## Examples
|
||||
|
||||
The following Pump code (where meta keywords start with `$`, `[[` and `]]` are
|
||||
meta brackets, and `$$` starts a meta comment that ends with the line):
|
||||
|
||||
```
|
||||
$var n = 3 $$ Defines a meta variable n.
|
||||
$range i 0..n $$ Declares the range of meta iterator i (inclusive).
|
||||
$for i [[
|
||||
$$ Meta loop.
|
||||
// Foo$i does blah for $i-ary predicates.
|
||||
$range j 1..i
|
||||
template <size_t N $for j [[, typename A$j]]>
|
||||
class Foo$i {
|
||||
$if i == 0 [[
|
||||
blah a;
|
||||
]] $elif i <= 2 [[
|
||||
blah b;
|
||||
]] $else [[
|
||||
blah c;
|
||||
]]
|
||||
};
|
||||
|
||||
]]
|
||||
```
|
||||
|
||||
will be translated by the Pump compiler to:
|
||||
|
||||
```cpp
|
||||
// Foo0 does blah for 0-ary predicates.
|
||||
template <size_t N>
|
||||
class Foo0 {
|
||||
blah a;
|
||||
};
|
||||
|
||||
// Foo1 does blah for 1-ary predicates.
|
||||
template <size_t N, typename A1>
|
||||
class Foo1 {
|
||||
blah b;
|
||||
};
|
||||
|
||||
// Foo2 does blah for 2-ary predicates.
|
||||
template <size_t N, typename A1, typename A2>
|
||||
class Foo2 {
|
||||
blah b;
|
||||
};
|
||||
|
||||
// Foo3 does blah for 3-ary predicates.
|
||||
template <size_t N, typename A1, typename A2, typename A3>
|
||||
class Foo3 {
|
||||
blah c;
|
||||
};
|
||||
```
|
||||
|
||||
In another example,
|
||||
|
||||
```
|
||||
$range i 1..n
|
||||
Func($for i + [[a$i]]);
|
||||
$$ The text between i and [[ is the separator between iterations.
|
||||
```
|
||||
|
||||
will generate one of the following lines (without the comments), depending on
|
||||
the value of `n`:
|
||||
|
||||
```cpp
|
||||
Func(); // If n is 0.
|
||||
Func(a1); // If n is 1.
|
||||
Func(a1 + a2); // If n is 2.
|
||||
Func(a1 + a2 + a3); // If n is 3.
|
||||
// And so on...
|
||||
```
|
||||
|
||||
## Constructs
|
||||
|
||||
We support the following meta programming constructs:
|
||||
|
||||
| `$var id = exp` | Defines a named constant value. `$id` is |
|
||||
: : valid until the end of the current meta :
|
||||
: : lexical block. :
|
||||
| :------------------------------- | :--------------------------------------- |
|
||||
| `$range id exp..exp` | Sets the range of an iteration variable, |
|
||||
: : which can be reused in multiple loops :
|
||||
: : later. :
|
||||
| `$for id sep [[ code ]]` | Iteration. The range of `id` must have |
|
||||
: : been defined earlier. `$id` is valid in :
|
||||
: : `code`. :
|
||||
| `$($)` | Generates a single `$` character. |
|
||||
| `$id` | Value of the named constant or iteration |
|
||||
: : variable. :
|
||||
| `$(exp)` | Value of the expression. |
|
||||
| `$if exp [[ code ]] else_branch` | Conditional. |
|
||||
| `[[ code ]]` | Meta lexical block. |
|
||||
| `cpp_code` | Raw C++ code. |
|
||||
| `$$ comment` | Meta comment. |
|
||||
|
||||
**Note:** To give the user some freedom in formatting the Pump source code, Pump
|
||||
ignores a new-line character if it's right after `$for foo` or next to `[[` or
|
||||
`]]`. Without this rule you'll often be forced to write very long lines to get
|
||||
the desired output. Therefore sometimes you may need to insert an extra new-line
|
||||
in such places for a new-line to show up in your output.
|
||||
|
||||
## Grammar
|
||||
|
||||
```ebnf
|
||||
code ::= atomic_code*
|
||||
atomic_code ::= $var id = exp
|
||||
| $var id = [[ code ]]
|
||||
| $range id exp..exp
|
||||
| $for id sep [[ code ]]
|
||||
| $($)
|
||||
| $id
|
||||
| $(exp)
|
||||
| $if exp [[ code ]] else_branch
|
||||
| [[ code ]]
|
||||
| cpp_code
|
||||
sep ::= cpp_code | empty_string
|
||||
else_branch ::= $else [[ code ]]
|
||||
| $elif exp [[ code ]] else_branch
|
||||
| empty_string
|
||||
exp ::= simple_expression_in_Python_syntax
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
You can find the source code of Pump in
|
||||
[googlemock/scripts/pump.py](../googlemock/scripts/pump.py). It is still very
|
||||
unpolished and lacks automated tests, although it has been successfully used
|
||||
many times. If you find a chance to use it in your project, please let us know
|
||||
what you think! We also welcome help on improving Pump.
|
||||
|
||||
## Real Examples
|
||||
|
||||
You can find real-world applications of Pump in
|
||||
[Google Test](https://github.com/google/googletest/tree/master/googletest) and
|
||||
[Google Mock](https://github.com/google/googletest/tree/master/googlemock). The
|
||||
source file `foo.h.pump` generates `foo.h`.
|
||||
|
||||
## Tips
|
||||
|
||||
* If a meta variable is followed by a letter or digit, you can separate them
|
||||
using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper`
|
||||
generate `Foo1Helper` when `j` is 1.
|
||||
* To avoid extra-long Pump source lines, you can break a line anywhere you
|
||||
want by inserting `[[]]` followed by a new line. Since any new-line
|
||||
character next to `[[` or `]]` is ignored, the generated code won't contain
|
||||
this new line.
|
@ -153,7 +153,6 @@ if (gmock_build_tests)
|
||||
cxx_test(gmock-cardinalities_test gmock_main)
|
||||
cxx_test(gmock_ex_test gmock_main)
|
||||
cxx_test(gmock-function-mocker_test gmock_main)
|
||||
cxx_test(gmock-generated-actions_test gmock_main)
|
||||
cxx_test(gmock-internal-utils_test gmock_main)
|
||||
cxx_test(gmock-matchers_test gmock_main)
|
||||
cxx_test(gmock-more-actions_test gmock_main)
|
||||
|
@ -1,390 +0,0 @@
|
||||
$$ -*- mode: c++; -*-
|
||||
$$ This is a Pump source file. Please use Pump to convert it to
|
||||
$$ gmock-generated-actions.h.
|
||||
$$
|
||||
$var n = 10 $$ The maximum arity we support.
|
||||
$$}} This meta comment fixes auto-indentation in editors.
|
||||
// Copyright 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
// Google Mock - a framework for writing C++ mock classes.
|
||||
//
|
||||
// This file implements some commonly used variadic actions.
|
||||
|
||||
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||
|
||||
#ifndef THIRD_PARTY_GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
|
||||
#define THIRD_PARTY_GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "gmock/gmock-actions.h"
|
||||
#include "gmock/internal/gmock-port.h"
|
||||
|
||||
// Include any custom callback actions added by the local installation.
|
||||
#include "gmock/internal/custom/gmock-generated-actions.h"
|
||||
|
||||
$range i 0..n
|
||||
$range k 0..n-1
|
||||
|
||||
// Sometimes you want to give an action explicit template parameters
|
||||
// that cannot be inferred from its value parameters. ACTION() and
|
||||
// ACTION_P*() don't support that. ACTION_TEMPLATE() remedies that
|
||||
// and can be viewed as an extension to ACTION() and ACTION_P*().
|
||||
//
|
||||
// The syntax:
|
||||
//
|
||||
// ACTION_TEMPLATE(ActionName,
|
||||
// HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m),
|
||||
// AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; }
|
||||
//
|
||||
// defines an action template that takes m explicit template
|
||||
// parameters and n value parameters. name_i is the name of the i-th
|
||||
// template parameter, and kind_i specifies whether it's a typename,
|
||||
// an integral constant, or a template. p_i is the name of the i-th
|
||||
// value parameter.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // DuplicateArg<k, T>(output) converts the k-th argument of the mock
|
||||
// // function to type T and copies it to *output.
|
||||
// ACTION_TEMPLATE(DuplicateArg,
|
||||
// HAS_2_TEMPLATE_PARAMS(int, k, typename, T),
|
||||
// AND_1_VALUE_PARAMS(output)) {
|
||||
// *output = T(::std::get<k>(args));
|
||||
// }
|
||||
// ...
|
||||
// int n;
|
||||
// EXPECT_CALL(mock, Foo(_, _))
|
||||
// .WillOnce(DuplicateArg<1, unsigned char>(&n));
|
||||
//
|
||||
// To create an instance of an action template, write:
|
||||
//
|
||||
// ActionName<t1, ..., t_m>(v1, ..., v_n)
|
||||
//
|
||||
// where the ts are the template arguments and the vs are the value
|
||||
// arguments. The value argument types are inferred by the compiler.
|
||||
// If you want to explicitly specify the value argument types, you can
|
||||
// provide additional template arguments:
|
||||
//
|
||||
// ActionName<t1, ..., t_m, u1, ..., u_k>(v1, ..., v_n)
|
||||
//
|
||||
// where u_i is the desired type of v_i.
|
||||
//
|
||||
// ACTION_TEMPLATE and ACTION/ACTION_P* can be overloaded on the
|
||||
// number of value parameters, but not on the number of template
|
||||
// parameters. Without the restriction, the meaning of the following
|
||||
// is unclear:
|
||||
//
|
||||
// OverloadedAction<int, bool>(x);
|
||||
//
|
||||
// Are we using a single-template-parameter action where 'bool' refers
|
||||
// to the type of x, or are we using a two-template-parameter action
|
||||
// where the compiler is asked to infer the type of x?
|
||||
//
|
||||
// Implementation notes:
|
||||
//
|
||||
// GMOCK_INTERNAL_*_HAS_m_TEMPLATE_PARAMS and
|
||||
// GMOCK_INTERNAL_*_AND_n_VALUE_PARAMS are internal macros for
|
||||
// implementing ACTION_TEMPLATE. The main trick we use is to create
|
||||
// new macro invocations when expanding a macro. For example, we have
|
||||
//
|
||||
// #define ACTION_TEMPLATE(name, template_params, value_params)
|
||||
// ... GMOCK_INTERNAL_DECL_##template_params ...
|
||||
//
|
||||
// which causes ACTION_TEMPLATE(..., HAS_1_TEMPLATE_PARAMS(typename, T), ...)
|
||||
// to expand to
|
||||
//
|
||||
// ... GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(typename, T) ...
|
||||
//
|
||||
// Since GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS is a macro, the
|
||||
// preprocessor will continue to expand it to
|
||||
//
|
||||
// ... typename T ...
|
||||
//
|
||||
// This technique conforms to the C++ standard and is portable. It
|
||||
// allows us to implement action templates using O(N) code, where N is
|
||||
// the maximum number of template/value parameters supported. Without
|
||||
// using it, we'd have to devote O(N^2) amount of code to implement all
|
||||
// combinations of m and n.
|
||||
|
||||
// Declares the template parameters.
|
||||
|
||||
$range j 1..n
|
||||
$for j [[
|
||||
$range m 0..j-1
|
||||
#define GMOCK_INTERNAL_DECL_HAS_$j[[]]
|
||||
_TEMPLATE_PARAMS($for m, [[kind$m, name$m]]) $for m, [[kind$m name$m]]
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// Lists the template parameters.
|
||||
|
||||
$for j [[
|
||||
$range m 0..j-1
|
||||
#define GMOCK_INTERNAL_LIST_HAS_$j[[]]
|
||||
_TEMPLATE_PARAMS($for m, [[kind$m, name$m]]) $for m, [[name$m]]
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// Declares the types of value parameters.
|
||||
|
||||
$for i [[
|
||||
$range j 0..i-1
|
||||
#define GMOCK_INTERNAL_DECL_TYPE_AND_$i[[]]
|
||||
_VALUE_PARAMS($for j, [[p$j]]) $for j [[, typename p$j##_type]]
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// Initializes the value parameters.
|
||||
|
||||
$for i [[
|
||||
$range j 0..i-1
|
||||
#define GMOCK_INTERNAL_INIT_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]])\
|
||||
($for j, [[p$j##_type gmock_p$j]])$if i>0 [[ : ]]$for j, [[p$j(::std::move(gmock_p$j))]]
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// Defines the copy constructor
|
||||
|
||||
$for i [[
|
||||
#define GMOCK_INTERNAL_DEFN_COPY_AND_$i[[]]_VALUE_PARAMS$if i == 0[[() \
|
||||
noexcept {} // Avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82134
|
||||
]] $else [[(...) = default;]]
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// Declares the fields for storing the value parameters.
|
||||
|
||||
$for i [[
|
||||
$range j 0..i-1
|
||||
#define GMOCK_INTERNAL_DEFN_AND_$i[[]]
|
||||
_VALUE_PARAMS($for j, [[p$j]]) $for j [[p$j##_type p$j; ]]
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// Lists the value parameters.
|
||||
|
||||
$for i [[
|
||||
$range j 0..i-1
|
||||
#define GMOCK_INTERNAL_LIST_AND_$i[[]]
|
||||
_VALUE_PARAMS($for j, [[p$j]]) $for j, [[p$j]]
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// Lists the value parameter types.
|
||||
|
||||
$for i [[
|
||||
$range j 0..i-1
|
||||
#define GMOCK_INTERNAL_LIST_TYPE_AND_$i[[]]
|
||||
_VALUE_PARAMS($for j, [[p$j]]) $for j [[, p$j##_type]]
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// Declares the value parameters.
|
||||
|
||||
$for i [[
|
||||
$range j 0..i-1
|
||||
#define GMOCK_INTERNAL_DECL_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]]) [[]]
|
||||
$for j, [[p$j##_type p$j]]
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// The suffix of the class template implementing the action template.
|
||||
$for i [[
|
||||
|
||||
|
||||
$range j 0..i-1
|
||||
#define GMOCK_INTERNAL_COUNT_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]]) [[]]
|
||||
$if i==1 [[P]] $elif i>=2 [[P$i]]
|
||||
]]
|
||||
|
||||
|
||||
// The name of the class template implementing the action template.
|
||||
#define GMOCK_ACTION_CLASS_(name, value_params)\
|
||||
GTEST_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params)
|
||||
|
||||
$range k 0..n-1
|
||||
|
||||
#define ACTION_TEMPLATE(name, template_params, value_params) \
|
||||
template <GMOCK_INTERNAL_DECL_##template_params \
|
||||
GMOCK_INTERNAL_DECL_TYPE_##value_params> \
|
||||
class GMOCK_ACTION_CLASS_(name, value_params) { \
|
||||
public: \
|
||||
explicit GMOCK_ACTION_CLASS_(name, value_params)( \
|
||||
GMOCK_INTERNAL_DECL_##value_params) \
|
||||
GMOCK_PP_IF(GMOCK_PP_IS_EMPTY(GMOCK_INTERNAL_COUNT_##value_params), \
|
||||
= default; , \
|
||||
: impl_(std::make_shared<gmock_Impl>( \
|
||||
GMOCK_INTERNAL_LIST_##value_params)) { }) \
|
||||
GMOCK_ACTION_CLASS_(name, value_params)( \
|
||||
const GMOCK_ACTION_CLASS_(name, value_params)&) \
|
||||
GMOCK_INTERNAL_DEFN_COPY_##value_params \
|
||||
GMOCK_ACTION_CLASS_(name, value_params)( \
|
||||
GMOCK_ACTION_CLASS_(name, value_params)&&) \
|
||||
GMOCK_INTERNAL_DEFN_COPY_##value_params \
|
||||
template <typename F> \
|
||||
operator ::testing::Action<F>() const { \
|
||||
return GMOCK_PP_IF( \
|
||||
GMOCK_PP_IS_EMPTY(GMOCK_INTERNAL_COUNT_##value_params), \
|
||||
(::testing::internal::MakeAction<F, gmock_Impl>()), \
|
||||
(::testing::internal::MakeAction<F>(impl_))); \
|
||||
} \
|
||||
private: \
|
||||
class gmock_Impl { \
|
||||
public: \
|
||||
explicit gmock_Impl GMOCK_INTERNAL_INIT_##value_params {} \
|
||||
template <typename function_type, typename return_type, \
|
||||
typename args_type, GMOCK_ACTION_TEMPLATE_ARGS_NAMES_> \
|
||||
return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \
|
||||
GMOCK_INTERNAL_DEFN_##value_params \
|
||||
}; \
|
||||
GMOCK_PP_IF(GMOCK_PP_IS_EMPTY(GMOCK_INTERNAL_COUNT_##value_params), \
|
||||
, std::shared_ptr<const gmock_Impl> impl_;) \
|
||||
}; \
|
||||
template <GMOCK_INTERNAL_DECL_##template_params \
|
||||
GMOCK_INTERNAL_DECL_TYPE_##value_params> \
|
||||
GMOCK_ACTION_CLASS_(name, value_params)< \
|
||||
GMOCK_INTERNAL_LIST_##template_params \
|
||||
GMOCK_INTERNAL_LIST_TYPE_##value_params> name( \
|
||||
GMOCK_INTERNAL_DECL_##value_params) GTEST_MUST_USE_RESULT_; \
|
||||
template <GMOCK_INTERNAL_DECL_##template_params \
|
||||
GMOCK_INTERNAL_DECL_TYPE_##value_params> \
|
||||
inline GMOCK_ACTION_CLASS_(name, value_params)< \
|
||||
GMOCK_INTERNAL_LIST_##template_params \
|
||||
GMOCK_INTERNAL_LIST_TYPE_##value_params> name( \
|
||||
GMOCK_INTERNAL_DECL_##value_params) { \
|
||||
return GMOCK_ACTION_CLASS_(name, value_params)< \
|
||||
GMOCK_INTERNAL_LIST_##template_params \
|
||||
GMOCK_INTERNAL_LIST_TYPE_##value_params>( \
|
||||
GMOCK_INTERNAL_LIST_##value_params); \
|
||||
} \
|
||||
template <GMOCK_INTERNAL_DECL_##template_params \
|
||||
GMOCK_INTERNAL_DECL_TYPE_##value_params> \
|
||||
template <typename function_type, typename return_type, typename args_type, \
|
||||
GMOCK_ACTION_TEMPLATE_ARGS_NAMES_> \
|
||||
return_type GMOCK_ACTION_CLASS_(name, value_params)< \
|
||||
GMOCK_INTERNAL_LIST_##template_params \
|
||||
GMOCK_INTERNAL_LIST_TYPE_##value_params>::gmock_Impl::gmock_PerformImpl( \
|
||||
GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
|
||||
|
||||
namespace testing {
|
||||
|
||||
// The ACTION*() macros trigger warning C4100 (unreferenced formal
|
||||
// parameter) in MSVC with -W4. Unfortunately they cannot be fixed in
|
||||
// the macro definition, as the warnings are generated when the macro
|
||||
// is expanded and macro expansion cannot contain #pragma. Therefore
|
||||
// we suppress them here.
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4100)
|
||||
#endif
|
||||
|
||||
namespace internal {
|
||||
|
||||
// internal::InvokeArgument - a helper for InvokeArgument action.
|
||||
// The basic overloads are provided here for generic functors.
|
||||
// Overloads for other custom-callables are provided in the
|
||||
// internal/custom/gmock-generated-actions.h header.
|
||||
template <typename F, typename... Args>
|
||||
auto InvokeArgument(F f, Args... args) -> decltype(f(args...)) {
|
||||
return f(args...);
|
||||
}
|
||||
|
||||
template <std::size_t index, typename... Params>
|
||||
struct InvokeArgumentAction {
|
||||
template <typename... Args>
|
||||
auto operator()(Args&&... args) const -> decltype(internal::InvokeArgument(
|
||||
std::get<index>(std::forward_as_tuple(std::forward<Args>(args)...)),
|
||||
std::declval<const Params&>()...)) {
|
||||
internal::FlatTuple<Args&&...> args_tuple(std::forward<Args>(args)...);
|
||||
return params.Apply([&](const Params&... unpacked_params) {
|
||||
auto&& callable = args_tuple.template Get<index>();
|
||||
return internal::InvokeArgument(
|
||||
std::forward<decltype(callable)>(callable), unpacked_params...);
|
||||
});
|
||||
}
|
||||
|
||||
internal::FlatTuple<Params...> params;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// The InvokeArgument<N>(a1, a2, ..., a_k) action invokes the N-th
|
||||
// (0-based) argument, which must be a k-ary callable, of the mock
|
||||
// function, with arguments a1, a2, ..., a_k.
|
||||
//
|
||||
// Notes:
|
||||
//
|
||||
// 1. The arguments are passed by value by default. If you need to
|
||||
// pass an argument by reference, wrap it inside std::ref(). For
|
||||
// example,
|
||||
//
|
||||
// InvokeArgument<1>(5, string("Hello"), std::ref(foo))
|
||||
//
|
||||
// passes 5 and string("Hello") by value, and passes foo by
|
||||
// reference.
|
||||
//
|
||||
// 2. If the callable takes an argument by reference but std::ref() is
|
||||
// not used, it will receive the reference to a copy of the value,
|
||||
// instead of the original value. For example, when the 0-th
|
||||
// argument of the mock function takes a const string&, the action
|
||||
//
|
||||
// InvokeArgument<0>(string("Hello"))
|
||||
//
|
||||
// makes a copy of the temporary string("Hello") object and passes a
|
||||
// reference of the copy, instead of the original temporary object,
|
||||
// to the callable. This makes it easy for a user to define an
|
||||
// InvokeArgument action from temporary values and have it performed
|
||||
// later.
|
||||
template <std::size_t index, typename... Params>
|
||||
internal::InvokeArgumentAction<index, typename std::decay<Params>::type...>
|
||||
InvokeArgument(Params&&... params) {
|
||||
return {internal::FlatTuple<typename std::decay<Params>::type...>(
|
||||
std::forward<Params>(params)...)};
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // THIRD_PARTY_GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
|
@ -1,7 +1,3 @@
|
||||
// This file was GENERATED by command:
|
||||
// pump.py gmock-generated-actions.h.pump
|
||||
// DO NOT EDIT BY HAND!!!
|
||||
|
||||
// Copyright 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
@ -38,8 +34,8 @@
|
||||
|
||||
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||
|
||||
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
|
||||
#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
|
||||
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
|
||||
#define GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
@ -574,4 +570,4 @@ InvokeArgument(Params&&... params) {
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
|
||||
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
|
@ -59,8 +59,8 @@
|
||||
#include "gmock/gmock-actions.h"
|
||||
#include "gmock/gmock-cardinalities.h"
|
||||
#include "gmock/gmock-function-mocker.h"
|
||||
#include "gmock/gmock-generated-actions.h"
|
||||
#include "gmock/gmock-matchers.h"
|
||||
#include "gmock/gmock-more-actions.h"
|
||||
#include "gmock/gmock-more-matchers.h"
|
||||
#include "gmock/gmock-nice-strict.h"
|
||||
#include "gmock/internal/gmock-internal-utils.h"
|
||||
|
@ -1,856 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2008, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""pump v0.2.0 - Pretty Useful for Meta Programming.
|
||||
|
||||
A tool for preprocessor meta programming. Useful for generating
|
||||
repetitive boilerplate code. Especially useful for writing C++
|
||||
classes, functions, macros, and templates that need to work with
|
||||
various number of arguments.
|
||||
|
||||
USAGE:
|
||||
pump.py SOURCE_FILE
|
||||
|
||||
EXAMPLES:
|
||||
pump.py foo.cc.pump
|
||||
Converts foo.cc.pump to foo.cc.
|
||||
|
||||
GRAMMAR:
|
||||
CODE ::= ATOMIC_CODE*
|
||||
ATOMIC_CODE ::= $var ID = EXPRESSION
|
||||
| $var ID = [[ CODE ]]
|
||||
| $range ID EXPRESSION..EXPRESSION
|
||||
| $for ID SEPARATOR [[ CODE ]]
|
||||
| $($)
|
||||
| $ID
|
||||
| $(EXPRESSION)
|
||||
| $if EXPRESSION [[ CODE ]] ELSE_BRANCH
|
||||
| [[ CODE ]]
|
||||
| RAW_CODE
|
||||
SEPARATOR ::= RAW_CODE | EMPTY
|
||||
ELSE_BRANCH ::= $else [[ CODE ]]
|
||||
| $elif EXPRESSION [[ CODE ]] ELSE_BRANCH
|
||||
| EMPTY
|
||||
EXPRESSION has Python syntax.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
TOKEN_TABLE = [
|
||||
(re.compile(r'\$var\s+'), '$var'),
|
||||
(re.compile(r'\$elif\s+'), '$elif'),
|
||||
(re.compile(r'\$else\s+'), '$else'),
|
||||
(re.compile(r'\$for\s+'), '$for'),
|
||||
(re.compile(r'\$if\s+'), '$if'),
|
||||
(re.compile(r'\$range\s+'), '$range'),
|
||||
(re.compile(r'\$[_A-Za-z]\w*'), '$id'),
|
||||
(re.compile(r'\$\(\$\)'), '$($)'),
|
||||
(re.compile(r'\$'), '$'),
|
||||
(re.compile(r'\[\[\n?'), '[['),
|
||||
(re.compile(r'\]\]\n?'), ']]'),
|
||||
]
|
||||
|
||||
|
||||
class Cursor:
|
||||
"""Represents a position (line and column) in a text file."""
|
||||
|
||||
def __init__(self, line=-1, column=-1):
|
||||
self.line = line
|
||||
self.column = column
|
||||
|
||||
def __eq__(self, rhs):
|
||||
return self.line == rhs.line and self.column == rhs.column
|
||||
|
||||
def __ne__(self, rhs):
|
||||
return not self == rhs
|
||||
|
||||
def __lt__(self, rhs):
|
||||
return self.line < rhs.line or (
|
||||
self.line == rhs.line and self.column < rhs.column)
|
||||
|
||||
def __le__(self, rhs):
|
||||
return self < rhs or self == rhs
|
||||
|
||||
def __gt__(self, rhs):
|
||||
return rhs < self
|
||||
|
||||
def __ge__(self, rhs):
|
||||
return rhs <= self
|
||||
|
||||
def __str__(self):
|
||||
if self == Eof():
|
||||
return 'EOF'
|
||||
else:
|
||||
return '%s(%s)' % (self.line + 1, self.column)
|
||||
|
||||
def __add__(self, offset):
|
||||
return Cursor(self.line, self.column + offset)
|
||||
|
||||
def __sub__(self, offset):
|
||||
return Cursor(self.line, self.column - offset)
|
||||
|
||||
def Clone(self):
|
||||
"""Returns a copy of self."""
|
||||
|
||||
return Cursor(self.line, self.column)
|
||||
|
||||
|
||||
# Special cursor to indicate the end-of-file.
|
||||
def Eof():
|
||||
"""Returns the special cursor to denote the end-of-file."""
|
||||
return Cursor(-1, -1)
|
||||
|
||||
|
||||
class Token:
|
||||
"""Represents a token in a Pump source file."""
|
||||
|
||||
def __init__(self, start=None, end=None, value=None, token_type=None):
|
||||
if start is None:
|
||||
self.start = Eof()
|
||||
else:
|
||||
self.start = start
|
||||
if end is None:
|
||||
self.end = Eof()
|
||||
else:
|
||||
self.end = end
|
||||
self.value = value
|
||||
self.token_type = token_type
|
||||
|
||||
def __str__(self):
|
||||
return 'Token @%s: \'%s\' type=%s' % (
|
||||
self.start, self.value, self.token_type)
|
||||
|
||||
def Clone(self):
|
||||
"""Returns a copy of self."""
|
||||
|
||||
return Token(self.start.Clone(), self.end.Clone(), self.value,
|
||||
self.token_type)
|
||||
|
||||
|
||||
def StartsWith(lines, pos, string):
|
||||
"""Returns True iff the given position in lines starts with 'string'."""
|
||||
|
||||
return lines[pos.line][pos.column:].startswith(string)
|
||||
|
||||
|
||||
def FindFirstInLine(line, token_table):
|
||||
best_match_start = -1
|
||||
for (regex, token_type) in token_table:
|
||||
m = regex.search(line)
|
||||
if m:
|
||||
# We found regex in lines
|
||||
if best_match_start < 0 or m.start() < best_match_start:
|
||||
best_match_start = m.start()
|
||||
best_match_length = m.end() - m.start()
|
||||
best_match_token_type = token_type
|
||||
|
||||
if best_match_start < 0:
|
||||
return None
|
||||
|
||||
return (best_match_start, best_match_length, best_match_token_type)
|
||||
|
||||
|
||||
def FindFirst(lines, token_table, cursor):
|
||||
"""Finds the first occurrence of any string in strings in lines."""
|
||||
|
||||
start = cursor.Clone()
|
||||
cur_line_number = cursor.line
|
||||
for line in lines[start.line:]:
|
||||
if cur_line_number == start.line:
|
||||
line = line[start.column:]
|
||||
m = FindFirstInLine(line, token_table)
|
||||
if m:
|
||||
# We found a regex in line.
|
||||
(start_column, length, token_type) = m
|
||||
if cur_line_number == start.line:
|
||||
start_column += start.column
|
||||
found_start = Cursor(cur_line_number, start_column)
|
||||
found_end = found_start + length
|
||||
return MakeToken(lines, found_start, found_end, token_type)
|
||||
cur_line_number += 1
|
||||
# We failed to find str in lines
|
||||
return None
|
||||
|
||||
|
||||
def SubString(lines, start, end):
|
||||
"""Returns a substring in lines."""
|
||||
|
||||
if end == Eof():
|
||||
end = Cursor(len(lines) - 1, len(lines[-1]))
|
||||
|
||||
if start >= end:
|
||||
return ''
|
||||
|
||||
if start.line == end.line:
|
||||
return lines[start.line][start.column:end.column]
|
||||
|
||||
result_lines = ([lines[start.line][start.column:]] +
|
||||
lines[start.line + 1:end.line] +
|
||||
[lines[end.line][:end.column]])
|
||||
return ''.join(result_lines)
|
||||
|
||||
|
||||
def StripMetaComments(str):
|
||||
"""Strip meta comments from each line in the given string."""
|
||||
|
||||
# First, completely remove lines containing nothing but a meta
|
||||
# comment, including the trailing \n.
|
||||
str = re.sub(r'^\s*\$\$.*\n', '', str)
|
||||
|
||||
# Then, remove meta comments from contentful lines.
|
||||
return re.sub(r'\s*\$\$.*', '', str)
|
||||
|
||||
|
||||
def MakeToken(lines, start, end, token_type):
|
||||
"""Creates a new instance of Token."""
|
||||
|
||||
return Token(start, end, SubString(lines, start, end), token_type)
|
||||
|
||||
|
||||
def ParseToken(lines, pos, regex, token_type):
|
||||
line = lines[pos.line][pos.column:]
|
||||
m = regex.search(line)
|
||||
if m and not m.start():
|
||||
return MakeToken(lines, pos, pos + m.end(), token_type)
|
||||
else:
|
||||
print('ERROR: %s expected at %s.' % (token_type, pos))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
ID_REGEX = re.compile(r'[_A-Za-z]\w*')
|
||||
EQ_REGEX = re.compile(r'=')
|
||||
REST_OF_LINE_REGEX = re.compile(r'.*?(?=$|\$\$)')
|
||||
OPTIONAL_WHITE_SPACES_REGEX = re.compile(r'\s*')
|
||||
WHITE_SPACE_REGEX = re.compile(r'\s')
|
||||
DOT_DOT_REGEX = re.compile(r'\.\.')
|
||||
|
||||
|
||||
def Skip(lines, pos, regex):
|
||||
line = lines[pos.line][pos.column:]
|
||||
m = re.search(regex, line)
|
||||
if m and not m.start():
|
||||
return pos + m.end()
|
||||
else:
|
||||
return pos
|
||||
|
||||
|
||||
def SkipUntil(lines, pos, regex, token_type):
|
||||
line = lines[pos.line][pos.column:]
|
||||
m = re.search(regex, line)
|
||||
if m:
|
||||
return pos + m.start()
|
||||
else:
|
||||
print ('ERROR: %s expected on line %s after column %s.' %
|
||||
(token_type, pos.line + 1, pos.column))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def ParseExpTokenInParens(lines, pos):
|
||||
def ParseInParens(pos):
|
||||
pos = Skip(lines, pos, OPTIONAL_WHITE_SPACES_REGEX)
|
||||
pos = Skip(lines, pos, r'\(')
|
||||
pos = Parse(pos)
|
||||
pos = Skip(lines, pos, r'\)')
|
||||
return pos
|
||||
|
||||
def Parse(pos):
|
||||
pos = SkipUntil(lines, pos, r'\(|\)', ')')
|
||||
if SubString(lines, pos, pos + 1) == '(':
|
||||
pos = Parse(pos + 1)
|
||||
pos = Skip(lines, pos, r'\)')
|
||||
return Parse(pos)
|
||||
else:
|
||||
return pos
|
||||
|
||||
start = pos.Clone()
|
||||
pos = ParseInParens(pos)
|
||||
return MakeToken(lines, start, pos, 'exp')
|
||||
|
||||
|
||||
def RStripNewLineFromToken(token):
|
||||
if token.value.endswith('\n'):
|
||||
return Token(token.start, token.end, token.value[:-1], token.token_type)
|
||||
else:
|
||||
return token
|
||||
|
||||
|
||||
def TokenizeLines(lines, pos):
|
||||
while True:
|
||||
found = FindFirst(lines, TOKEN_TABLE, pos)
|
||||
if not found:
|
||||
yield MakeToken(lines, pos, Eof(), 'code')
|
||||
return
|
||||
|
||||
if found.start == pos:
|
||||
prev_token = None
|
||||
prev_token_rstripped = None
|
||||
else:
|
||||
prev_token = MakeToken(lines, pos, found.start, 'code')
|
||||
prev_token_rstripped = RStripNewLineFromToken(prev_token)
|
||||
|
||||
if found.token_type == '$var':
|
||||
if prev_token_rstripped:
|
||||
yield prev_token_rstripped
|
||||
yield found
|
||||
id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
|
||||
yield id_token
|
||||
pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX)
|
||||
|
||||
eq_token = ParseToken(lines, pos, EQ_REGEX, '=')
|
||||
yield eq_token
|
||||
pos = Skip(lines, eq_token.end, r'\s*')
|
||||
|
||||
if SubString(lines, pos, pos + 2) != '[[':
|
||||
exp_token = ParseToken(lines, pos, REST_OF_LINE_REGEX, 'exp')
|
||||
yield exp_token
|
||||
pos = Cursor(exp_token.end.line + 1, 0)
|
||||
elif found.token_type == '$for':
|
||||
if prev_token_rstripped:
|
||||
yield prev_token_rstripped
|
||||
yield found
|
||||
id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
|
||||
yield id_token
|
||||
pos = Skip(lines, id_token.end, WHITE_SPACE_REGEX)
|
||||
elif found.token_type == '$range':
|
||||
if prev_token_rstripped:
|
||||
yield prev_token_rstripped
|
||||
yield found
|
||||
id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
|
||||
yield id_token
|
||||
pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX)
|
||||
|
||||
dots_pos = SkipUntil(lines, pos, DOT_DOT_REGEX, '..')
|
||||
yield MakeToken(lines, pos, dots_pos, 'exp')
|
||||
yield MakeToken(lines, dots_pos, dots_pos + 2, '..')
|
||||
pos = dots_pos + 2
|
||||
new_pos = Cursor(pos.line + 1, 0)
|
||||
yield MakeToken(lines, pos, new_pos, 'exp')
|
||||
pos = new_pos
|
||||
elif found.token_type == '$':
|
||||
if prev_token:
|
||||
yield prev_token
|
||||
yield found
|
||||
exp_token = ParseExpTokenInParens(lines, found.end)
|
||||
yield exp_token
|
||||
pos = exp_token.end
|
||||
elif (found.token_type == ']]' or found.token_type == '$if' or
|
||||
found.token_type == '$elif' or found.token_type == '$else'):
|
||||
if prev_token_rstripped:
|
||||
yield prev_token_rstripped
|
||||
yield found
|
||||
pos = found.end
|
||||
else:
|
||||
if prev_token:
|
||||
yield prev_token
|
||||
yield found
|
||||
pos = found.end
|
||||
|
||||
|
||||
def Tokenize(s):
|
||||
"""A generator that yields the tokens in the given string."""
|
||||
if s != '':
|
||||
lines = s.splitlines(True)
|
||||
for token in TokenizeLines(lines, Cursor(0, 0)):
|
||||
yield token
|
||||
|
||||
|
||||
class CodeNode:
|
||||
def __init__(self, atomic_code_list=None):
|
||||
self.atomic_code = atomic_code_list
|
||||
|
||||
|
||||
class VarNode:
|
||||
def __init__(self, identifier=None, atomic_code=None):
|
||||
self.identifier = identifier
|
||||
self.atomic_code = atomic_code
|
||||
|
||||
|
||||
class RangeNode:
|
||||
def __init__(self, identifier=None, exp1=None, exp2=None):
|
||||
self.identifier = identifier
|
||||
self.exp1 = exp1
|
||||
self.exp2 = exp2
|
||||
|
||||
|
||||
class ForNode:
|
||||
def __init__(self, identifier=None, sep=None, code=None):
|
||||
self.identifier = identifier
|
||||
self.sep = sep
|
||||
self.code = code
|
||||
|
||||
|
||||
class ElseNode:
|
||||
def __init__(self, else_branch=None):
|
||||
self.else_branch = else_branch
|
||||
|
||||
|
||||
class IfNode:
|
||||
def __init__(self, exp=None, then_branch=None, else_branch=None):
|
||||
self.exp = exp
|
||||
self.then_branch = then_branch
|
||||
self.else_branch = else_branch
|
||||
|
||||
|
||||
class RawCodeNode:
|
||||
def __init__(self, token=None):
|
||||
self.raw_code = token
|
||||
|
||||
|
||||
class LiteralDollarNode:
|
||||
def __init__(self, token):
|
||||
self.token = token
|
||||
|
||||
|
||||
class ExpNode:
|
||||
def __init__(self, token, python_exp):
|
||||
self.token = token
|
||||
self.python_exp = python_exp
|
||||
|
||||
|
||||
def PopFront(a_list):
|
||||
head = a_list[0]
|
||||
a_list[:1] = []
|
||||
return head
|
||||
|
||||
|
||||
def PushFront(a_list, elem):
|
||||
a_list[:0] = [elem]
|
||||
|
||||
|
||||
def PopToken(a_list, token_type=None):
|
||||
token = PopFront(a_list)
|
||||
if token_type is not None and token.token_type != token_type:
|
||||
print('ERROR: %s expected at %s' % (token_type, token.start))
|
||||
print('ERROR: %s found instead' % (token,))
|
||||
sys.exit(1)
|
||||
|
||||
return token
|
||||
|
||||
|
||||
def PeekToken(a_list):
|
||||
if not a_list:
|
||||
return None
|
||||
|
||||
return a_list[0]
|
||||
|
||||
|
||||
def ParseExpNode(token):
|
||||
python_exp = re.sub(r'([_A-Za-z]\w*)', r'self.GetValue("\1")', token.value)
|
||||
return ExpNode(token, python_exp)
|
||||
|
||||
|
||||
def ParseElseNode(tokens):
|
||||
def Pop(token_type=None):
|
||||
return PopToken(tokens, token_type)
|
||||
|
||||
next = PeekToken(tokens)
|
||||
if not next:
|
||||
return None
|
||||
if next.token_type == '$else':
|
||||
Pop('$else')
|
||||
Pop('[[')
|
||||
code_node = ParseCodeNode(tokens)
|
||||
Pop(']]')
|
||||
return code_node
|
||||
elif next.token_type == '$elif':
|
||||
Pop('$elif')
|
||||
exp = Pop('code')
|
||||
Pop('[[')
|
||||
code_node = ParseCodeNode(tokens)
|
||||
Pop(']]')
|
||||
inner_else_node = ParseElseNode(tokens)
|
||||
return CodeNode([IfNode(ParseExpNode(exp), code_node, inner_else_node)])
|
||||
elif not next.value.strip():
|
||||
Pop('code')
|
||||
return ParseElseNode(tokens)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def ParseAtomicCodeNode(tokens):
|
||||
def Pop(token_type=None):
|
||||
return PopToken(tokens, token_type)
|
||||
|
||||
head = PopFront(tokens)
|
||||
t = head.token_type
|
||||
if t == 'code':
|
||||
return RawCodeNode(head)
|
||||
elif t == '$var':
|
||||
id_token = Pop('id')
|
||||
Pop('=')
|
||||
next = PeekToken(tokens)
|
||||
if next.token_type == 'exp':
|
||||
exp_token = Pop()
|
||||
return VarNode(id_token, ParseExpNode(exp_token))
|
||||
Pop('[[')
|
||||
code_node = ParseCodeNode(tokens)
|
||||
Pop(']]')
|
||||
return VarNode(id_token, code_node)
|
||||
elif t == '$for':
|
||||
id_token = Pop('id')
|
||||
next_token = PeekToken(tokens)
|
||||
if next_token.token_type == 'code':
|
||||
sep_token = next_token
|
||||
Pop('code')
|
||||
else:
|
||||
sep_token = None
|
||||
Pop('[[')
|
||||
code_node = ParseCodeNode(tokens)
|
||||
Pop(']]')
|
||||
return ForNode(id_token, sep_token, code_node)
|
||||
elif t == '$if':
|
||||
exp_token = Pop('code')
|
||||
Pop('[[')
|
||||
code_node = ParseCodeNode(tokens)
|
||||
Pop(']]')
|
||||
else_node = ParseElseNode(tokens)
|
||||
return IfNode(ParseExpNode(exp_token), code_node, else_node)
|
||||
elif t == '$range':
|
||||
id_token = Pop('id')
|
||||
exp1_token = Pop('exp')
|
||||
Pop('..')
|
||||
exp2_token = Pop('exp')
|
||||
return RangeNode(id_token, ParseExpNode(exp1_token),
|
||||
ParseExpNode(exp2_token))
|
||||
elif t == '$id':
|
||||
return ParseExpNode(Token(head.start + 1, head.end, head.value[1:], 'id'))
|
||||
elif t == '$($)':
|
||||
return LiteralDollarNode(head)
|
||||
elif t == '$':
|
||||
exp_token = Pop('exp')
|
||||
return ParseExpNode(exp_token)
|
||||
elif t == '[[':
|
||||
code_node = ParseCodeNode(tokens)
|
||||
Pop(']]')
|
||||
return code_node
|
||||
else:
|
||||
PushFront(tokens, head)
|
||||
return None
|
||||
|
||||
|
||||
def ParseCodeNode(tokens):
|
||||
atomic_code_list = []
|
||||
while True:
|
||||
if not tokens:
|
||||
break
|
||||
atomic_code_node = ParseAtomicCodeNode(tokens)
|
||||
if atomic_code_node:
|
||||
atomic_code_list.append(atomic_code_node)
|
||||
else:
|
||||
break
|
||||
return CodeNode(atomic_code_list)
|
||||
|
||||
|
||||
def ParseToAST(pump_src_text):
|
||||
"""Convert the given Pump source text into an AST."""
|
||||
tokens = list(Tokenize(pump_src_text))
|
||||
code_node = ParseCodeNode(tokens)
|
||||
return code_node
|
||||
|
||||
|
||||
class Env:
|
||||
def __init__(self):
|
||||
self.variables = []
|
||||
self.ranges = []
|
||||
|
||||
def Clone(self):
|
||||
clone = Env()
|
||||
clone.variables = self.variables[:]
|
||||
clone.ranges = self.ranges[:]
|
||||
return clone
|
||||
|
||||
def PushVariable(self, var, value):
|
||||
# If value looks like an int, store it as an int.
|
||||
try:
|
||||
int_value = int(value)
|
||||
if ('%s' % int_value) == value:
|
||||
value = int_value
|
||||
except Exception:
|
||||
pass
|
||||
self.variables[:0] = [(var, value)]
|
||||
|
||||
def PopVariable(self):
|
||||
self.variables[:1] = []
|
||||
|
||||
def PushRange(self, var, lower, upper):
|
||||
self.ranges[:0] = [(var, lower, upper)]
|
||||
|
||||
def PopRange(self):
|
||||
self.ranges[:1] = []
|
||||
|
||||
def GetValue(self, identifier):
|
||||
for (var, value) in self.variables:
|
||||
if identifier == var:
|
||||
return value
|
||||
|
||||
print('ERROR: meta variable %s is undefined.' % (identifier,))
|
||||
sys.exit(1)
|
||||
|
||||
def EvalExp(self, exp):
|
||||
try:
|
||||
result = eval(exp.python_exp)
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
print('ERROR: caught exception %s: %s' % (e.__class__.__name__, e))
|
||||
print('ERROR: failed to evaluate meta expression %s at %s' %
|
||||
(exp.python_exp, exp.token.start))
|
||||
sys.exit(1)
|
||||
return result
|
||||
|
||||
def GetRange(self, identifier):
|
||||
for (var, lower, upper) in self.ranges:
|
||||
if identifier == var:
|
||||
return (lower, upper)
|
||||
|
||||
print('ERROR: range %s is undefined.' % (identifier,))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class Output:
|
||||
def __init__(self):
|
||||
self.string = ''
|
||||
|
||||
def GetLastLine(self):
|
||||
index = self.string.rfind('\n')
|
||||
if index < 0:
|
||||
return ''
|
||||
|
||||
return self.string[index + 1:]
|
||||
|
||||
def Append(self, s):
|
||||
self.string += s
|
||||
|
||||
|
||||
def RunAtomicCode(env, node, output):
|
||||
if isinstance(node, VarNode):
|
||||
identifier = node.identifier.value.strip()
|
||||
result = Output()
|
||||
RunAtomicCode(env.Clone(), node.atomic_code, result)
|
||||
value = result.string
|
||||
env.PushVariable(identifier, value)
|
||||
elif isinstance(node, RangeNode):
|
||||
identifier = node.identifier.value.strip()
|
||||
lower = int(env.EvalExp(node.exp1))
|
||||
upper = int(env.EvalExp(node.exp2))
|
||||
env.PushRange(identifier, lower, upper)
|
||||
elif isinstance(node, ForNode):
|
||||
identifier = node.identifier.value.strip()
|
||||
if node.sep is None:
|
||||
sep = ''
|
||||
else:
|
||||
sep = node.sep.value
|
||||
(lower, upper) = env.GetRange(identifier)
|
||||
for i in range(lower, upper + 1):
|
||||
new_env = env.Clone()
|
||||
new_env.PushVariable(identifier, i)
|
||||
RunCode(new_env, node.code, output)
|
||||
if i != upper:
|
||||
output.Append(sep)
|
||||
elif isinstance(node, RawCodeNode):
|
||||
output.Append(node.raw_code.value)
|
||||
elif isinstance(node, IfNode):
|
||||
cond = env.EvalExp(node.exp)
|
||||
if cond:
|
||||
RunCode(env.Clone(), node.then_branch, output)
|
||||
elif node.else_branch is not None:
|
||||
RunCode(env.Clone(), node.else_branch, output)
|
||||
elif isinstance(node, ExpNode):
|
||||
value = env.EvalExp(node)
|
||||
output.Append('%s' % (value,))
|
||||
elif isinstance(node, LiteralDollarNode):
|
||||
output.Append('$')
|
||||
elif isinstance(node, CodeNode):
|
||||
RunCode(env.Clone(), node, output)
|
||||
else:
|
||||
print('BAD')
|
||||
print(node)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def RunCode(env, code_node, output):
|
||||
for atomic_code in code_node.atomic_code:
|
||||
RunAtomicCode(env, atomic_code, output)
|
||||
|
||||
|
||||
def IsSingleLineComment(cur_line):
|
||||
return '//' in cur_line
|
||||
|
||||
|
||||
def IsInPreprocessorDirective(prev_lines, cur_line):
|
||||
if cur_line.lstrip().startswith('#'):
|
||||
return True
|
||||
return prev_lines and prev_lines[-1].endswith('\\')
|
||||
|
||||
|
||||
def WrapComment(line, output):
|
||||
loc = line.find('//')
|
||||
before_comment = line[:loc].rstrip()
|
||||
if before_comment == '':
|
||||
indent = loc
|
||||
else:
|
||||
output.append(before_comment)
|
||||
indent = len(before_comment) - len(before_comment.lstrip())
|
||||
prefix = indent*' ' + '// '
|
||||
max_len = 80 - len(prefix)
|
||||
comment = line[loc + 2:].strip()
|
||||
segs = [seg for seg in re.split(r'(\w+\W*)', comment) if seg != '']
|
||||
cur_line = ''
|
||||
for seg in segs:
|
||||
if len((cur_line + seg).rstrip()) < max_len:
|
||||
cur_line += seg
|
||||
else:
|
||||
if cur_line.strip() != '':
|
||||
output.append(prefix + cur_line.rstrip())
|
||||
cur_line = seg.lstrip()
|
||||
if cur_line.strip() != '':
|
||||
output.append(prefix + cur_line.strip())
|
||||
|
||||
|
||||
def WrapCode(line, line_concat, output):
|
||||
indent = len(line) - len(line.lstrip())
|
||||
prefix = indent*' ' # Prefix of the current line
|
||||
max_len = 80 - indent - len(line_concat) # Maximum length of the current line
|
||||
new_prefix = prefix + 4*' ' # Prefix of a continuation line
|
||||
new_max_len = max_len - 4 # Maximum length of a continuation line
|
||||
# Prefers to wrap a line after a ',' or ';'.
|
||||
segs = [seg for seg in re.split(r'([^,;]+[,;]?)', line.strip()) if seg != '']
|
||||
cur_line = '' # The current line without leading spaces.
|
||||
for seg in segs:
|
||||
# If the line is still too long, wrap at a space.
|
||||
while cur_line == '' and len(seg.strip()) > max_len:
|
||||
seg = seg.lstrip()
|
||||
split_at = seg.rfind(' ', 0, max_len)
|
||||
output.append(prefix + seg[:split_at].strip() + line_concat)
|
||||
seg = seg[split_at + 1:]
|
||||
prefix = new_prefix
|
||||
max_len = new_max_len
|
||||
|
||||
if len((cur_line + seg).rstrip()) < max_len:
|
||||
cur_line = (cur_line + seg).lstrip()
|
||||
else:
|
||||
output.append(prefix + cur_line.rstrip() + line_concat)
|
||||
prefix = new_prefix
|
||||
max_len = new_max_len
|
||||
cur_line = seg.lstrip()
|
||||
if cur_line.strip() != '':
|
||||
output.append(prefix + cur_line.strip())
|
||||
|
||||
|
||||
def WrapPreprocessorDirective(line, output):
|
||||
WrapCode(line, ' \\', output)
|
||||
|
||||
|
||||
def WrapPlainCode(line, output):
|
||||
WrapCode(line, '', output)
|
||||
|
||||
|
||||
def IsMultiLineIWYUPragma(line):
|
||||
return re.search(r'/\* IWYU pragma: ', line)
|
||||
|
||||
|
||||
def IsHeaderGuardIncludeOrOneLineIWYUPragma(line):
|
||||
return (re.match(r'^#(ifndef|define|endif\s*//)\s*[\w_]+\s*$', line) or
|
||||
re.match(r'^#include\s', line) or
|
||||
# Don't break IWYU pragmas, either; that causes iwyu.py problems.
|
||||
re.search(r'// IWYU pragma: ', line))
|
||||
|
||||
|
||||
def WrapLongLine(line, output):
|
||||
line = line.rstrip()
|
||||
if len(line) <= 80:
|
||||
output.append(line)
|
||||
elif IsSingleLineComment(line):
|
||||
if IsHeaderGuardIncludeOrOneLineIWYUPragma(line):
|
||||
# The style guide made an exception to allow long header guard lines,
|
||||
# includes and IWYU pragmas.
|
||||
output.append(line)
|
||||
else:
|
||||
WrapComment(line, output)
|
||||
elif IsInPreprocessorDirective(output, line):
|
||||
if IsHeaderGuardIncludeOrOneLineIWYUPragma(line):
|
||||
# The style guide made an exception to allow long header guard lines,
|
||||
# includes and IWYU pragmas.
|
||||
output.append(line)
|
||||
else:
|
||||
WrapPreprocessorDirective(line, output)
|
||||
elif IsMultiLineIWYUPragma(line):
|
||||
output.append(line)
|
||||
else:
|
||||
WrapPlainCode(line, output)
|
||||
|
||||
|
||||
def BeautifyCode(string):
|
||||
lines = string.splitlines()
|
||||
output = []
|
||||
for line in lines:
|
||||
WrapLongLine(line, output)
|
||||
output2 = [line.rstrip() for line in output]
|
||||
return '\n'.join(output2) + '\n'
|
||||
|
||||
|
||||
def ConvertFromPumpSource(src_text):
|
||||
"""Return the text generated from the given Pump source text."""
|
||||
ast = ParseToAST(StripMetaComments(src_text))
|
||||
output = Output()
|
||||
RunCode(Env(), ast, output)
|
||||
return BeautifyCode(output.string)
|
||||
|
||||
|
||||
def main(argv):
|
||||
if len(argv) == 1:
|
||||
print(__doc__)
|
||||
sys.exit(1)
|
||||
|
||||
file_path = argv[-1]
|
||||
output_str = ConvertFromPumpSource(io.open(file_path, 'r').read())
|
||||
if file_path.endswith('.pump'):
|
||||
output_file_path = file_path[:-5]
|
||||
else:
|
||||
output_file_path = '-'
|
||||
if output_file_path == '-':
|
||||
print(output_str,)
|
||||
else:
|
||||
output_file = io.open(output_file_path, 'w')
|
||||
output_file.write(u'// This file was GENERATED by command:\n')
|
||||
output_file.write(u'// %s %s\n' %
|
||||
(os.path.basename(__file__), os.path.basename(file_path)))
|
||||
output_file.write(u'// DO NOT EDIT BY HAND!!!\n\n')
|
||||
output_file.write(output_str)
|
||||
output_file.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv)
|
@ -1,170 +0,0 @@
|
||||
// Copyright 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
// Google Mock - a framework for writing C++ mock classes.
|
||||
//
|
||||
// This file contains negative compilation tests for script-generated
|
||||
// Google Mock actions.
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
using testing::Action;
|
||||
using testing::Invoke;
|
||||
using testing::WithArgs;
|
||||
|
||||
int Nullary() { return 0; }
|
||||
int Binary(int a, int b) { return a + b; }
|
||||
|
||||
#if defined(TEST_NULLARY_WITH_ARGS)
|
||||
|
||||
// Tests that WithArgs(action) doesn't compile.
|
||||
void Test() {
|
||||
Action<int(int)> a = WithArgs(Invoke(Nullary));
|
||||
}
|
||||
|
||||
#elif defined(TEST_TOO_FEW_ARGS_FOR_WITH_ARGS)
|
||||
|
||||
// Tests that you cannot pass too few arguments to the inner action in
|
||||
// WithArgs().
|
||||
void Test() {
|
||||
Action<int(int, int, int)> a = WithArgs<1>(Invoke(Binary));
|
||||
}
|
||||
|
||||
#elif defined(TEST_TOO_MANY_ARGS_FOR_WITH_ARGS)
|
||||
|
||||
// Tests that you cannot pass too many arguments to the inner action in
|
||||
// WithArgs().
|
||||
void Test() {
|
||||
Action<int(int, int, int)> a = WithArgs<1, 2, 0>(Invoke(Binary));
|
||||
}
|
||||
|
||||
#elif defined(TEST_INCOMPATIBLE_ARG_TYPES_FOR_WITH_ARGS)
|
||||
|
||||
// Tests that you cannot pass arguments of incompatible types to the
|
||||
// inner action in WithArgs().
|
||||
void Test() {
|
||||
Action<int(int, const char*, int)> a = WithArgs<1, 2>(Invoke(Binary));
|
||||
}
|
||||
|
||||
#elif defined(TEST_WRONG_ARG_TYPE_IN_ACTION_MACRO)
|
||||
|
||||
// Tests using an ACTION definition in a mock function whose argument
|
||||
// types are incompatible.
|
||||
ACTION(WrongArgType) { return 10/arg0; }
|
||||
|
||||
void Test() {
|
||||
Action<int(const char*)> a = WrongArgType();
|
||||
}
|
||||
|
||||
#elif defined(TEST_WRONG_RETURN_TYPE_IN_ACTION_MACRO)
|
||||
|
||||
// Tests using an ACTION definition in a mock function whose return
|
||||
// types is incompatible.
|
||||
ACTION(WrongReturnType) { return 10; }
|
||||
|
||||
void Test() {
|
||||
Action<const char*()> a = WrongReturnType();
|
||||
}
|
||||
|
||||
#elif defined(TEST_EXCESSIVE_ARG_IN_ACTION_MACRO)
|
||||
|
||||
// Tests using an ACTION definition in a mock function that doesn't
|
||||
// provide enough arguments.
|
||||
ACTION(UseExcessiveArg) { return arg0 + arg1; }
|
||||
|
||||
void Test() {
|
||||
Action<int(int)> a = UseExcessiveArg();
|
||||
}
|
||||
|
||||
#elif defined(TEST_ACTION_MACRO_IN_CLASS)
|
||||
|
||||
// Tests using ACTION in a class scope.
|
||||
class Foo {
|
||||
public:
|
||||
// This won't compile as C++ doesn't allow defining a method of a
|
||||
// nested class out-of-line in the enclosing class.
|
||||
ACTION(Bar) { return arg0; }
|
||||
};
|
||||
|
||||
#elif defined(TEST_ACTION_MACRO_IN_FUNCTION)
|
||||
|
||||
// Tests using ACTION in a function body.
|
||||
void Test() {
|
||||
// This won't compile as C++ doesn't allow member templates in local
|
||||
// classes. We may want to revisit this when C++0x is widely
|
||||
// implemented.
|
||||
ACTION(Bar) { return arg0; }
|
||||
}
|
||||
|
||||
#elif defined(TEST_SET_ARG_REFEREE_MUST_BE_USED_WITH_REFERENCE)
|
||||
|
||||
// Verifies that using SetArgReferee<k>(...) where the k-th argument
|
||||
// of the mock function is not a reference generates a compiler error.
|
||||
void Test() {
|
||||
Action<void(bool, int)> a = testing::SetArgReferee<1>(5);
|
||||
}
|
||||
|
||||
#elif defined(TEST_DELETE_ARG_MUST_BE_USED_WITH_POINTER)
|
||||
|
||||
// Verifies that using DeleteArg<k>(...) where the k-th argument of the mock
|
||||
// function is not a pointer generates a compiler error.
|
||||
void Test() {
|
||||
Action<void(int)> a = testing::DeleteArg<0>(); // NOLINT
|
||||
}
|
||||
|
||||
#elif defined(TEST_CANNOT_OVERLOAD_ACTION_TEMPLATE_ON_TEMPLATE_PARAM_NUMBER)
|
||||
|
||||
// Tests that ACTION_TEMPLATE cannot be overloaded on the number of
|
||||
// template parameters alone.
|
||||
|
||||
ACTION_TEMPLATE(OverloadedAction,
|
||||
HAS_1_TEMPLATE_PARAMS(typename, T),
|
||||
AND_1_VALUE_PARAMS(p)) {}
|
||||
|
||||
ACTION_TEMPLATE(OverloadedAction,
|
||||
HAS_2_TEMPLATE_PARAMS(typename, T1, typename, T2),
|
||||
AND_1_VALUE_PARAMS(p)) {}
|
||||
|
||||
#elif defined(TEST_CANNOT_OVERLOAD_ACTION_AND_ACTION_TEMPLATE_W_SAME_VALUE_PS)
|
||||
|
||||
// Tests that ACTION_TEMPLATE and ACTION_P cannot be overloaded when
|
||||
// they have the same number of value parameters.
|
||||
|
||||
ACTION_P(OverloadedAction, p) {}
|
||||
|
||||
ACTION_TEMPLATE(OverloadedAction,
|
||||
HAS_1_TEMPLATE_PARAMS(typename, T),
|
||||
AND_1_VALUE_PARAMS(p)) {}
|
||||
|
||||
#else
|
||||
|
||||
// Sanity check - this should compile.
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -37,7 +37,6 @@
|
||||
// below list of actual *_test.cc files might change).
|
||||
#include "test/gmock-actions_test.cc"
|
||||
#include "test/gmock-cardinalities_test.cc"
|
||||
#include "test/gmock-generated-actions_test.cc"
|
||||
#include "test/gmock-internal-utils_test.cc"
|
||||
#include "test/gmock-matchers_test.cc"
|
||||
#include "test/gmock-more-actions_test.cc"
|
||||
|
@ -1,137 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2008, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Google Mock - a framework for writing C++ mock classes.
|
||||
#
|
||||
# This file drives the negative compilation tests for script-generated
|
||||
# Google Mock actions.
|
||||
|
||||
"""Driver for the NC tests for script-generated Google Mock actions."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
IS_LINUX = os.name == "posix" and os.uname()[0] == "Linux"
|
||||
if not IS_LINUX:
|
||||
sys.stderr.write(
|
||||
"WARNING: Negative compilation tests are not supported on this platform")
|
||||
sys.exit(0)
|
||||
|
||||
# Suppresses the 'Import not at the top of the file' lint complaint.
|
||||
# pylint: disable-msg=C6204
|
||||
from google3.testing.pybase import fake_target_util
|
||||
from google3.testing.pybase import googletest
|
||||
# pylint: enable-msg=C6204
|
||||
|
||||
|
||||
class GMockGeneratedActionTest(googletest.TestCase):
|
||||
"""Negative compilation tests for generated Google Mock actions."""
|
||||
|
||||
# The class body is intentionally empty. The actual test*() methods
|
||||
# will be defined at run time by a call to
|
||||
# DefineNegativeCompilationTests() later.
|
||||
pass
|
||||
|
||||
# Defines a list of test specs, where each element is a tuple
|
||||
# (test name, list of regexes for matching the compiler errors).
|
||||
TEST_SPECS = [
|
||||
("NULLARY_WITH_ARGS", [
|
||||
r"no matching function for call to 'WithArgs",
|
||||
]),
|
||||
("TOO_FEW_ARGS_FOR_WITH_ARGS", [
|
||||
r"no known conversion",
|
||||
]),
|
||||
("TOO_MANY_ARGS_FOR_WITH_ARGS", [
|
||||
r"no known conversion",
|
||||
]),
|
||||
("INCOMPATIBLE_ARG_TYPES_FOR_WITH_ARGS", [
|
||||
r"no known conversion",
|
||||
]),
|
||||
("WRONG_ARG_TYPE_IN_ACTION_MACRO", [
|
||||
r"invalid operands",
|
||||
]),
|
||||
(
|
||||
"WRONG_RETURN_TYPE_IN_ACTION_MACRO",
|
||||
[
|
||||
r"invalid conversion", # GCC
|
||||
r"cannot initialize return object", # Clang
|
||||
]),
|
||||
(
|
||||
"EXCESSIVE_ARG_IN_ACTION_MACRO",
|
||||
[
|
||||
r"no match for 'operator\+'", # GCC
|
||||
r"invalid operands to binary expression", # Clang
|
||||
]),
|
||||
(
|
||||
"ACTION_MACRO_IN_CLASS",
|
||||
[
|
||||
r"cannot define member function.*Bar.*within.*Foo", # GCC
|
||||
r"ACTION\(Bar\)", # Clang
|
||||
]),
|
||||
(
|
||||
"ACTION_MACRO_IN_FUNCTION",
|
||||
[
|
||||
r"invalid declaration of member template in local class", # GCC
|
||||
r"templates cannot be declared inside of a local class", # Clang
|
||||
]),
|
||||
("SET_ARG_REFEREE_MUST_BE_USED_WITH_REFERENCE",
|
||||
[r"Argument must be a reference type"]),
|
||||
(
|
||||
"DELETE_ARG_MUST_BE_USED_WITH_POINTER",
|
||||
[
|
||||
r"argument given to 'delete', expected pointer", # GCC
|
||||
r"cannot delete expression of type", # Clang
|
||||
]),
|
||||
(
|
||||
"CANNOT_OVERLOAD_ACTION_TEMPLATE_ON_TEMPLATE_PARAM_NUMBER",
|
||||
[
|
||||
r"wrong number of template arguments", # GCC
|
||||
r"too many template parameters", # Clang
|
||||
]),
|
||||
(
|
||||
"CANNOT_OVERLOAD_ACTION_AND_ACTION_TEMPLATE_W_SAME_VALUE_PS",
|
||||
[
|
||||
r"wrong number of template arguments", # GCC
|
||||
r"too many template parameters", # Clang
|
||||
]),
|
||||
("SANITY", None),
|
||||
]
|
||||
|
||||
# Define a test method in GMockGeneratedActionTest for each element in
|
||||
# TEST_SPECS.
|
||||
fake_target_util.DefineNegativeCompilationTests(
|
||||
GMockGeneratedActionTest,
|
||||
"google3/third_party/googletest/googlemock/test/gmock-generated-actions_nc", # fake target
|
||||
"gmock-generated-actions_nc.o", # object file
|
||||
TEST_SPECS)
|
||||
|
||||
if __name__ == "__main__":
|
||||
googletest.main()
|
@ -1,182 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2010, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Tests for the Pump meta-programming tool."""
|
||||
|
||||
from google3.testing.pybase import googletest
|
||||
import google3.third_party.googletest.googlemock.scripts.pump
|
||||
|
||||
pump = google3.third_party.googletest.googlemock.scripts.pump
|
||||
Convert = pump.ConvertFromPumpSource
|
||||
StripMetaComments = pump.StripMetaComments
|
||||
|
||||
|
||||
class PumpTest(googletest.TestCase):
|
||||
|
||||
def testConvertsEmptyToEmpty(self):
|
||||
self.assertEquals('', Convert('').strip())
|
||||
|
||||
def testConvertsPlainCodeToSame(self):
|
||||
self.assertEquals('#include <stdio.h>\n',
|
||||
Convert('#include <stdio.h>\n'))
|
||||
|
||||
def testConvertsLongIWYUPragmaToSame(self):
|
||||
long_line = '// IWYU pragma: private, include "' + (80*'a') + '.h"\n'
|
||||
self.assertEquals(long_line, Convert(long_line))
|
||||
|
||||
def testConvertsIWYUPragmaWithLeadingSpaceToSame(self):
|
||||
long_line = ' // IWYU pragma: private, include "' + (80*'a') + '.h"\n'
|
||||
self.assertEquals(long_line, Convert(long_line))
|
||||
|
||||
def testConvertsIWYUPragmaWithSlashStarLeaderToSame(self):
|
||||
long_line = '/* IWYU pragma: private, include "' + (80*'a') + '.h"\n'
|
||||
self.assertEquals(long_line, Convert(long_line))
|
||||
|
||||
def testConvertsIWYUPragmaWithSlashStarAndSpacesToSame(self):
|
||||
long_line = ' /* IWYU pragma: private, include "' + (80*'a') + '.h"\n'
|
||||
self.assertEquals(long_line, Convert(long_line))
|
||||
|
||||
def testIgnoresMetaComment(self):
|
||||
self.assertEquals('',
|
||||
Convert('$$ This is a Pump meta comment.\n').strip())
|
||||
|
||||
def testSimpleVarDeclarationWorks(self):
|
||||
self.assertEquals('3\n',
|
||||
Convert('$var m = 3\n'
|
||||
'$m\n'))
|
||||
|
||||
def testVarDeclarationCanReferenceEarlierVar(self):
|
||||
self.assertEquals('43 != 3;\n',
|
||||
Convert('$var a = 42\n'
|
||||
'$var b = a + 1\n'
|
||||
'$var c = (b - a)*3\n'
|
||||
'$b != $c;\n'))
|
||||
|
||||
def testSimpleLoopWorks(self):
|
||||
self.assertEquals('1, 2, 3, 4, 5\n',
|
||||
Convert('$var n = 5\n'
|
||||
'$range i 1..n\n'
|
||||
'$for i, [[$i]]\n'))
|
||||
|
||||
def testSimpleLoopWithCommentWorks(self):
|
||||
self.assertEquals('1, 2, 3, 4, 5\n',
|
||||
Convert('$var n = 5 $$ This is comment 1.\n'
|
||||
'$range i 1..n $$ This is comment 2.\n'
|
||||
'$for i, [[$i]]\n'))
|
||||
|
||||
def testNonTrivialRangeExpressionsWork(self):
|
||||
self.assertEquals('1, 2, 3, 4\n',
|
||||
Convert('$var n = 5\n'
|
||||
'$range i (n/n)..(n - 1)\n'
|
||||
'$for i, [[$i]]\n'))
|
||||
|
||||
def testLoopWithoutSeparatorWorks(self):
|
||||
self.assertEquals('a + 1 + 2 + 3;\n',
|
||||
Convert('$range i 1..3\n'
|
||||
'a$for i [[ + $i]];\n'))
|
||||
|
||||
def testCanGenerateDollarSign(self):
|
||||
self.assertEquals('$\n', Convert('$($)\n'))
|
||||
|
||||
def testCanIterpolateExpressions(self):
|
||||
self.assertEquals('a[2] = 3;\n',
|
||||
Convert('$var i = 1\n'
|
||||
'a[$(i + 1)] = $(i*4 - 1);\n'))
|
||||
|
||||
def testConditionalWithoutElseBranchWorks(self):
|
||||
self.assertEquals('true\n',
|
||||
Convert('$var n = 5\n'
|
||||
'$if n > 0 [[true]]\n'))
|
||||
|
||||
def testConditionalWithElseBranchWorks(self):
|
||||
self.assertEquals('true -- really false\n',
|
||||
Convert('$var n = 5\n'
|
||||
'$if n > 0 [[true]]\n'
|
||||
'$else [[false]] -- \n'
|
||||
'$if n > 10 [[really true]]\n'
|
||||
'$else [[really false]]\n'))
|
||||
|
||||
def testConditionalWithCascadingElseBranchWorks(self):
|
||||
self.assertEquals('a\n',
|
||||
Convert('$var n = 5\n'
|
||||
'$if n > 0 [[a]]\n'
|
||||
'$elif n > 10 [[b]]\n'
|
||||
'$else [[c]]\n'))
|
||||
self.assertEquals('b\n',
|
||||
Convert('$var n = 5\n'
|
||||
'$if n > 10 [[a]]\n'
|
||||
'$elif n > 0 [[b]]\n'
|
||||
'$else [[c]]\n'))
|
||||
self.assertEquals('c\n',
|
||||
Convert('$var n = 5\n'
|
||||
'$if n > 10 [[a]]\n'
|
||||
'$elif n > 8 [[b]]\n'
|
||||
'$else [[c]]\n'))
|
||||
|
||||
def testNestedLexicalBlocksWork(self):
|
||||
self.assertEquals('a = 5;\n',
|
||||
Convert('$var n = 5\n'
|
||||
'a = [[$if n > 0 [[$n]]]];\n'))
|
||||
|
||||
|
||||
class StripMetaCommentsTest(googletest.TestCase):
|
||||
|
||||
def testReturnsSameStringIfItContainsNoComment(self):
|
||||
self.assertEquals('', StripMetaComments(''))
|
||||
self.assertEquals(' blah ', StripMetaComments(' blah '))
|
||||
self.assertEquals('A single $ is fine.',
|
||||
StripMetaComments('A single $ is fine.'))
|
||||
self.assertEquals('multiple\nlines',
|
||||
StripMetaComments('multiple\nlines'))
|
||||
|
||||
def testStripsSimpleComment(self):
|
||||
self.assertEquals('yes\n', StripMetaComments('yes $$ or no?\n'))
|
||||
|
||||
def testStripsSimpleCommentWithMissingNewline(self):
|
||||
self.assertEquals('yes', StripMetaComments('yes $$ or no?'))
|
||||
|
||||
def testStripsPureCommentLinesEntirely(self):
|
||||
self.assertEquals('yes\n',
|
||||
StripMetaComments('$$ a pure comment line.\n'
|
||||
'yes $$ or no?\n'
|
||||
' $$ another comment line.\n'))
|
||||
|
||||
def testStripsCommentsFromMultiLineText(self):
|
||||
self.assertEquals('multi-\n'
|
||||
'line\n'
|
||||
'text is fine.',
|
||||
StripMetaComments('multi- $$ comment 1\n'
|
||||
'line\n'
|
||||
'text is fine. $$ comment 2'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
googletest.main()
|
Loading…
Reference in New Issue
Block a user