/* * dyngen helpers * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ int __op_param1, __op_param2, __op_param3; #if defined(__sparc__) || defined(__arm__) void __op_gen_label1(){} void __op_gen_label2(){} void __op_gen_label3(){} #else int __op_gen_label1, __op_gen_label2, __op_gen_label3; #endif int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #ifdef __i386__ static inline void flush_icache_range(unsigned long start, unsigned long stop) { } #endif #ifdef __x86_64__ static inline void flush_icache_range(unsigned long start, unsigned long stop) { } #endif #ifdef __s390__ static inline void flush_icache_range(unsigned long start, unsigned long stop) { } #endif #ifdef __ia64__ static inline void flush_icache_range(unsigned long start, unsigned long stop) { while (start < stop) { asm volatile ("fc %0" :: "r"(start)); start += 32; } asm volatile (";;sync.i;;srlz.i;;"); } #endif #ifdef __powerpc__ #define MIN_CACHE_LINE_SIZE 8 /* conservative value */ static void inline flush_icache_range(unsigned long start, unsigned long stop) { unsigned long p; start &= ~(MIN_CACHE_LINE_SIZE - 1); stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); } asm volatile ("sync" : : : "memory"); for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); } asm volatile ("sync" : : : "memory"); asm volatile ("isync" : : : "memory"); } #endif #ifdef __alpha__ static inline void flush_icache_range(unsigned long start, unsigned long stop) { asm ("imb"); } #endif #ifdef __sparc__ static void inline flush_icache_range(unsigned long start, unsigned long stop) { unsigned long p; p = start & ~(8UL - 1UL); stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL); for (; p < stop; p += 8) __asm__ __volatile__("flush\t%0" : : "r" (p)); } #endif #ifdef __arm__ static inline void flush_icache_range(unsigned long start, unsigned long stop) { register unsigned long _beg __asm ("a1") = start; register unsigned long _end __asm ("a2") = stop; register unsigned long _flg __asm ("a3") = 0; __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); } #endif #ifdef __mc68000 #include static inline void flush_icache_range(unsigned long start, unsigned long stop) { cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16); } #endif #ifdef __alpha__ register int gp asm("$29"); static inline void immediate_ldah(void *p, int val) { uint32_t *dest = p; long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff; *dest &= ~0xffff; *dest |= high; *dest |= 31 << 16; } static inline void immediate_lda(void *dest, int val) { *(uint16_t *) dest = val; } void fix_bsr(void *p, int offset) { uint32_t *dest = p; *dest &= ~((1 << 21) - 1); *dest |= (offset >> 2) & ((1 << 21) - 1); } #endif /* __alpha__ */ #ifdef __arm__ #define ARM_LDR_TABLE_SIZE 1024 typedef struct LDREntry { uint8_t *ptr; uint32_t *data_ptr; unsigned type:2; } LDREntry; static LDREntry arm_ldr_table[1024]; static uint32_t arm_data_table[ARM_LDR_TABLE_SIZE]; extern char exec_loop; static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val) { *ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff); } static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, LDREntry *ldr_start, LDREntry *ldr_end, uint32_t *data_start, uint32_t *data_end, int gen_jmp) { LDREntry *le; uint32_t *ptr; int offset, data_size, target; uint8_t *data_ptr; uint32_t insn; uint32_t mask; data_size = (data_end - data_start) << 2; if (gen_jmp) { /* generate branch to skip the data */ if (data_size == 0) return gen_code_ptr; target = (long)gen_code_ptr + data_size + 4; arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target); gen_code_ptr += 4; } /* copy the data */ data_ptr = gen_code_ptr; memcpy(gen_code_ptr, data_start, data_size); gen_code_ptr += data_size; /* patch the ldr to point to the data */ for(le = ldr_start; le < ldr_end; le++) { ptr = (uint32_t *)le->ptr; offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) + (unsigned long)data_ptr - (unsigned long)ptr - 8; if (offset < 0) { fprintf(stderr, "Negative constant pool offset\n"); abort(); } switch (le->type) { case 0: /* ldr */ mask = ~0x00800fff; if (offset >= 4096) { fprintf(stderr, "Bad ldr offset\n"); abort(); } break; case 1: /* ldc */ mask = ~0x008000ff; if (offset >= 1024 ) { fprintf(stderr, "Bad ldc offset\n"); abort(); } break; case 2: /* add */ mask = ~0xfff; if (offset >= 1024 ) { fprintf(stderr, "Bad add offset\n"); abort(); } break; default: fprintf(stderr, "Bad pc relative fixup\n"); abort(); } insn = *ptr & mask; switch (le->type) { case 0: /* ldr */ insn |= offset | 0x00800000; break; case 1: /* ldc */ insn |= (offset >> 2) | 0x00800000; break; case 2: /* add */ insn |= (offset >> 2) | 0xf00; break; } *ptr = insn; } return gen_code_ptr; } #endif /* __arm__ */ #ifdef __ia64 /* Patch instruction with "val" where "mask" has 1 bits. */ static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val) { uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16); # define insn_mask ((1UL << 41) - 1) unsigned long shift; b0 = b[0]; b1 = b[1]; shift = 5 + 41 * (insn_addr % 16); /* 5 template, 3 x 41-bit insns */ if (shift >= 64) { m1 = mask << (shift - 64); v1 = val << (shift - 64); } else { m0 = mask << shift; m1 = mask >> (64 - shift); v0 = val << shift; v1 = val >> (64 - shift); b[0] = (b0 & ~m0) | (v0 & m0); } b[1] = (b1 & ~m1) | (v1 & m1); } static inline void ia64_patch_imm60 (uint64_t insn_addr, uint64_t val) { ia64_patch(insn_addr, 0x011ffffe000UL, ( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */ | ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */)); ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18); } static inline void ia64_imm64 (void *insn, uint64_t val) { /* Ignore the slot number of the relocation; GCC and Intel toolchains differed for some time on whether IMM64 relocs are against slot 1 (Intel) or slot 2 (GCC). */ uint64_t insn_addr = (uint64_t) insn & ~3UL; ia64_patch(insn_addr + 2, 0x01fffefe000UL, ( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */ | ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */ | ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */ | ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */ | ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */) ); ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22); } static inline void ia64_imm60b (void *insn, uint64_t val) { /* Ignore the slot number of the relocation; GCC and Intel toolchains differed for some time on whether IMM64 relocs are against slot 1 (Intel) or slot 2 (GCC). */ uint64_t insn_addr = (uint64_t) insn & ~3UL; if (val + ((uint64_t) 1 << 59) >= (1UL << 60)) fprintf(stderr, "%s: value %ld out of IMM60 range\n", __FUNCTION__, (int64_t) val); ia64_patch_imm60(insn_addr + 2, val); } static inline void ia64_imm22 (void *insn, uint64_t val) { if (val + (1 << 21) >= (1 << 22)) fprintf(stderr, "%s: value %li out of IMM22 range\n", __FUNCTION__, (int64_t)val); ia64_patch((uint64_t) insn, 0x01fffcfe000UL, ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); } /* Like ia64_imm22(), but also clear bits 20-21. For addl, this has the effect of turning "addl rX=imm22,rY" into "addl rX=imm22,r0". */ static inline void ia64_imm22_r0 (void *insn, uint64_t val) { if (val + (1 << 21) >= (1 << 22)) fprintf(stderr, "%s: value %li out of IMM22 range\n", __FUNCTION__, (int64_t)val); ia64_patch((uint64_t) insn, 0x01fffcfe000UL | (0x3UL << 20), ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); } static inline void ia64_imm21b (void *insn, uint64_t val) { if (val + (1 << 20) >= (1 << 21)) fprintf(stderr, "%s: value %li out of IMM21b range\n", __FUNCTION__, (int64_t)val); ia64_patch((uint64_t) insn, 0x11ffffe000UL, ( ((val & 0x100000UL) << 16) /* bit 20 -> 36 */ | ((val & 0x0fffffUL) << 13) /* bit 0 -> 13 */)); } static inline void ia64_nop_b (void *insn) { ia64_patch((uint64_t) insn, (1UL << 41) - 1, 2UL << 37); } static inline void ia64_ldxmov(void *insn, uint64_t val) { if (val + (1 << 21) < (1 << 22)) ia64_patch((uint64_t) insn, 0x1fff80fe000UL, 8UL << 37); } static inline int ia64_patch_ltoff(void *insn, uint64_t val, int relaxable) { if (relaxable && (val + (1 << 21) < (1 << 22))) { ia64_imm22_r0(insn, val); return 0; } return 1; } struct ia64_fixup { struct ia64_fixup *next; void *addr; /* address that needs to be patched */ long value; }; #define IA64_PLT(insn, plt_index) \ do { \ struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \ fixup->next = plt_fixes; \ plt_fixes = fixup; \ fixup->addr = (insn); \ fixup->value = (plt_index); \ plt_offset[(plt_index)] = 1; \ } while (0) #define IA64_LTOFF(insn, val, relaxable) \ do { \ if (ia64_patch_ltoff(insn, val, relaxable)) { \ struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \ fixup->next = ltoff_fixes; \ ltoff_fixes = fixup; \ fixup->addr = (insn); \ fixup->value = (val); \ } \ } while (0) static inline void ia64_apply_fixes (uint8_t **gen_code_pp, struct ia64_fixup *ltoff_fixes, uint64_t gp, struct ia64_fixup *plt_fixes, int num_plts, unsigned long *plt_target, unsigned int *plt_offset) { static const uint8_t plt_bundle[] = { 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; movl r1=GP */ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; brl IP */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0 }; uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start, *vp; struct ia64_fixup *fixup; unsigned int offset = 0; struct fdesc { long ip; long gp; } *fdesc; int i; if (plt_fixes) { plt_start = gen_code_ptr; for (i = 0; i < num_plts; ++i) { if (plt_offset[i]) { plt_offset[i] = offset; offset += sizeof(plt_bundle); fdesc = (struct fdesc *) plt_target[i]; memcpy(gen_code_ptr, plt_bundle, sizeof(plt_bundle)); ia64_imm64 (gen_code_ptr + 0x02, fdesc->gp); ia64_imm60b(gen_code_ptr + 0x12, (fdesc->ip - (long) (gen_code_ptr + 0x10)) >> 4); gen_code_ptr += sizeof(plt_bundle); } } for (fixup = plt_fixes; fixup; fixup = fixup->next) ia64_imm21b(fixup->addr, ((long) plt_start + plt_offset[fixup->value] - ((long) fixup->addr & ~0xf)) >> 4); } got_start = gen_code_ptr; /* First, create the GOT: */ for (fixup = ltoff_fixes; fixup; fixup = fixup->next) { /* first check if we already have this value in the GOT: */ for (vp = got_start; vp < gen_code_ptr; ++vp) if (*(uint64_t *) vp == fixup->value) break; if (vp == gen_code_ptr) { /* Nope, we need to put the value in the GOT: */ *(uint64_t *) vp = fixup->value; gen_code_ptr += 8; } ia64_imm22(fixup->addr, (long) vp - gp); } /* Keep code ptr aligned. */ if ((long) gen_code_ptr & 15) gen_code_ptr += 8; *gen_code_pp = gen_code_ptr; } #endif 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
// 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.
//
// Author: wan@google.com (Zhanyong Wan)

// Google Mock - a framework for writing C++ mock classes.
//
// This file tests the built-in actions in gmock-more-actions.h.

#include "gmock/gmock-more-actions.h"

#include <functional>
#include <sstream>
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "gtest/internal/gtest-linked_ptr.h"

namespace testing {
namespace gmock_more_actions_test {

using ::std::plus;
using ::std::string;
using testing::get;
using testing::make_tuple;
using testing::tuple;
using testing::tuple_element;
using testing::_;
using testing::Action;
using testing::ActionInterface;
using testing::DeleteArg;
using testing::Invoke;
using testing::Return;
using testing::ReturnArg;
using testing::ReturnPointee;
using testing::SaveArg;
using testing::SaveArgPointee;
using testing::SetArgReferee;
using testing::StaticAssertTypeEq;
using testing::Unused;
using testing::WithArg;
using testing::WithoutArgs;
using testing::internal::linked_ptr;

// For suppressing compiler warnings on conversion possibly losing precision.
inline short Short(short n) { return n; }  // NOLINT
inline char Char(char ch) { return ch; }

// Sample functions and functors for testing Invoke() and etc.
int Nullary() { return 1; }

class NullaryFunctor {
 public:
  int operator()() { return 2; }
};

bool g_done = false;
void VoidNullary() { g_done = true; }

class VoidNullaryFunctor {
 public:
  void operator()() { g_done = true; }
};

bool Unary(int x) { return x < 0; }

const char* Plus1(const char* s) { return s + 1; }

void VoidUnary(int /* n */) { g_done = true; }

bool ByConstRef(const string& s) { return s == "Hi"; }

const double g_double = 0;
bool ReferencesGlobalDouble(const double& x) { return &x == &g_double; }

string ByNonConstRef(string& s) { return s += "+"; }  // NOLINT

struct UnaryFunctor {
  int operator()(bool x) { return x ? 1 : -1; }
};

const char* Binary(const char* input, short n) { return input + n; }  // NOLINT

void VoidBinary(int, char) { g_done = true; }

int Ternary(int x, char y, short z) { return x + y + z; }  // NOLINT

void VoidTernary(int, char, bool) { g_done = true; }

int SumOf4(int a, int b, int c, int d) { return a + b + c + d; }

int SumOfFirst2(int a, int b, Unused, Unused) { return a + b; }

void VoidFunctionWithFourArguments(char, int, float, double) { g_done = true; }

string Concat4(const char* s1, const char* s2, const char* s3,
               const char* s4) {
  return string(s1) + s2 + s3 + s4;
}

int SumOf5(int a, int b, int c, int d, int e) { return a + b + c + d + e; }

struct SumOf5Functor {
  int operator()(int a, int b, int c, int d, int e) {
    return a + b + c + d + e;
  }
};

string Concat5(const char* s1, const char* s2, const char* s3,
               const char* s4, const char* s5) {
  return string(s1) + s2 + s3 + s4 + s5;
}

int SumOf6(int a, int b, int c, int d, int e, int f) {
  return a + b + c + d + e + f;
}

struct SumOf6Functor {
  int operator()(int a, int b, int c, int d, int e, int f) {
    return a + b + c + d + e + f;
  }
};

string Concat6(const char* s1, const char* s2, const char* s3,
               const char* s4, const char* s5, const char* s6) {
  return string(s1) + s2 + s3 + s4 + s5 + s6;
}

string Concat7(const char* s1, const char* s2, const char* s3,
               const char* s4, const char* s5, const char* s6,
               const char* s7) {
  return string(s1) + s2 + s3 + s4 + s5 + s6 + s7;
}

string Concat8(const char* s1, const char* s2, const char* s3,
               const char* s4, const char* s5, const char* s6,
               const char* s7, const char* s8) {
  return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8;
}

string Concat9(const char* s1, const char* s2, const char* s3,
               const char* s4, const char* s5, const char* s6,
               const char* s7, const char* s8, const char* s9) {
  return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9;
}

string Concat10(const char* s1, const char* s2, const char* s3,
                const char* s4, const char* s5, const char* s6,
                const char* s7, const char* s8, const char* s9,
                const char* s10) {
  return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10;
}

class Foo {
 public:
  Foo() : value_(123) {}

  int Nullary() const { return value_; }

  short Unary(long x) { return static_cast<short>(value_ + x); }  // NOLINT

  string Binary(const string& str, char c) const { return str + c; }

  int Ternary(int x, bool y, char z) { return value_ + x + y*z; }

  int SumOf4(int a, int b, int c, int d) const {
    return a + b + c + d + value_;
  }

  int SumOfLast2(Unused, Unused, int a, int b) const { return a + b; }

  int SumOf5(int a, int b, int c, int d, int e) { return a + b + c + d + e; }

  int SumOf6(int a, int b, int c, int d, int e, int f) {
    return a + b + c + d + e + f;
  }

  string Concat7(const char* s1, const char* s2, const char* s3,
                 const char* s4, const char* s5, const char* s6,
                 const char* s7) {
    return string(s1) + s2 + s3 + s4 + s5 + s6 + s7;
  }

  string Concat8(const char* s1, const char* s2, const char* s3,
                 const char* s4, const char* s5, const char* s6,
                 const char* s7, const char* s8) {
    return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8;
  }

  string Concat9(const char* s1, const char* s2, const char* s3,
                 const char* s4, const char* s5, const char* s6,
                 const char* s7, const char* s8, const char* s9) {
    return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9;
  }

  string Concat10(const char* s1, const char* s2, const char* s3,
                  const char* s4, const char* s5, const char* s6,
                  const char* s7, const char* s8, const char* s9,
                  const char* s10) {
    return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10;
  }

 private:
  int value_;
};

// Tests using Invoke() with a nullary function.
TEST(InvokeTest, Nullary) {
  Action<int()> a = Invoke(Nullary);  // NOLINT
  EXPECT_EQ(1, a.Perform(make_tuple()));
}

// Tests using Invoke() with a unary function.
TEST(InvokeTest, Unary) {
  Action<bool(int)> a = Invoke(Unary);  // NOLINT
  EXPECT_FALSE(a.Perform(make_tuple(1)));
  EXPECT_TRUE(a.Perform(make_tuple(-1)));
}

// Tests using Invoke() with a binary function.
TEST(InvokeTest, Binary) {
  Action<const char*(const char*, short)> a = Invoke(Binary);  // NOLINT
  const char* p = "Hello";
  EXPECT_EQ(p + 2, a.Perform(make_tuple(p, Short(2))));
}

// Tests using Invoke() with a ternary function.
TEST(InvokeTest, Ternary) {
  Action<int(int, char, short)> a = Invoke(Ternary);  // NOLINT
  EXPECT_EQ(6, a.Perform(make_tuple(1, '\2', Short(3))));
}

// Tests using Invoke() with a 4-argument function.
TEST(InvokeTest, FunctionThatTakes4Arguments) {
  Action<int(int, int, int, int)> a = Invoke(SumOf4);  // NOLINT
  EXPECT_EQ(1234, a.Perform(make_tuple(1000, 200, 30, 4)));
}

// Tests using Invoke() with a 5-argument function.
TEST(InvokeTest, FunctionThatTakes5Arguments) {
  Action<int(int, int, int, int, int)> a = Invoke(SumOf5);  // NOLINT
  EXPECT_EQ(12345, a.Perform(make_tuple(10000, 2000, 300, 40, 5)));
}

// Tests using Invoke() with a 6-argument function.
TEST(InvokeTest, FunctionThatTakes6Arguments) {
  Action<int(int, int, int, int, int, int)> a = Invoke(SumOf6);  // NOLINT
  EXPECT_EQ(123456, a.Perform(make_tuple(100000, 20000, 3000, 400, 50, 6)));
}

// A helper that turns the type of a C-string literal from const
// char[N] to const char*.
inline const char* CharPtr(const char* s) { return s; }

// Tests using Invoke() with a 7-argument function.
TEST(InvokeTest, FunctionThatTakes7Arguments) {
  Action<string(const char*, const char*, const char*, const char*,
                const char*, const char*, const char*)> a =
      Invoke(Concat7);
  EXPECT_EQ("1234567",
            a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"),
                                 CharPtr("4"), CharPtr("5"), CharPtr("6"),
                                 CharPtr("7"))));
}

// Tests using Invoke() with a 8-argument function.
TEST(InvokeTest, FunctionThatTakes8Arguments) {
  Action<string(const char*, const char*, const char*, const char*,
                const char*, const char*, const char*, const char*)> a =
      Invoke(Concat8);
  EXPECT_EQ("12345678",
            a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"),
                                 CharPtr("4"), CharPtr("5"), CharPtr("6"),
                                 CharPtr("7"), CharPtr("8"))));
}

// Tests using Invoke() with a 9-argument function.
TEST(InvokeTest, FunctionThatTakes9Arguments) {
  Action<string(const char*, const char*, const char*, const char*,
                const char*, const char*, const char*, const char*,
                const char*)> a = Invoke(Concat9);
  EXPECT_EQ("123456789",
            a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"),
                                 CharPtr("4"), CharPtr("5"), CharPtr("6"),
                                 CharPtr("7"), CharPtr("8"), CharPtr("9"))));
}

// Tests using Invoke() with a 10-argument function.
TEST(InvokeTest, FunctionThatTakes10Arguments) {
  Action<string(const char*, const char*, const char*, const char*,
                const char*, const char*, const char*, const char*,
                const char*, const char*)> a = Invoke(Concat10);
  EXPECT_EQ("1234567890",
            a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"),
                                 CharPtr("4"), CharPtr("5"), CharPtr("6"),
                                 CharPtr("7"), CharPtr("8"), CharPtr("9"),
                                 CharPtr("0"))));
}

// Tests using Invoke() with functions with parameters declared as Unused.
TEST(InvokeTest, FunctionWithUnusedParameters) {
  Action<int(int, int, double, const string&)> a1 =
      Invoke(SumOfFirst2);
  string s("hi");
  EXPECT_EQ(12, a1.Perform(
    tuple<int, int, double, const string&>(10, 2, 5.6, s)));

  Action<int(int, int, bool, int*)> a2 =
      Invoke(SumOfFirst2);
  EXPECT_EQ(23, a2.Perform(make_tuple(20, 3, true, static_cast<int*>(NULL))));
}

// Tests using Invoke() with methods with parameters declared as Unused.
TEST(InvokeTest, MethodWithUnusedParameters) {
  Foo foo;
  Action<int(string, bool, int, int)> a1 =
      Invoke(&foo, &Foo::SumOfLast2);
  EXPECT_EQ(12, a1.Perform(make_tuple(CharPtr("hi"), true, 10, 2)));

  Action<int(char, double, int, int)> a2 =
      Invoke(&foo, &Foo::SumOfLast2);
  EXPECT_EQ(23, a2.Perform(make_tuple('a', 2.5, 20, 3)));
}

// Tests using Invoke() with a functor.
TEST(InvokeTest, Functor) {
  Action<long(long, int)> a = Invoke(plus<long>());  // NOLINT
  EXPECT_EQ(3L, a.Perform(make_tuple(1, 2)));
}

// Tests using Invoke(f) as an action of a compatible type.
TEST(InvokeTest, FunctionWithCompatibleType) {
  Action<long(int, short, char, bool)> a = Invoke(SumOf4);  // NOLINT
  EXPECT_EQ(4321, a.Perform(make_tuple(4000, Short(300), Char(20), true)));
}

// Tests using Invoke() with an object pointer and a method pointer.

// Tests using Invoke() with a nullary method.
TEST(InvokeMethodTest, Nullary) {
  Foo foo;
  Action<int()> a = Invoke(&foo, &Foo::Nullary);  // NOLINT
  EXPECT_EQ(123, a.Perform(make_tuple()));
}

// Tests using Invoke() with a unary method.
TEST(InvokeMethodTest, Unary) {
  Foo foo;
  Action<short(long)> a = Invoke(&foo, &Foo::Unary);  // NOLINT
  EXPECT_EQ(4123, a.Perform(make_tuple(4000)));
}

// Tests using Invoke() with a binary method.
TEST(InvokeMethodTest, Binary) {
  Foo foo;
  Action<string(const string&, char)> a = Invoke(&foo, &Foo::Binary);
  string s("Hell");
  EXPECT_EQ("Hello", a.Perform(
      tuple<const string&, char>(s, 'o')));
}

// Tests using Invoke() with a ternary method.
TEST(InvokeMethodTest, Ternary) {
  Foo foo;
  Action<int(int, bool, char)> a = Invoke(&foo, &Foo::Ternary);  // NOLINT
  EXPECT_EQ(1124, a.Perform(make_tuple(1000, true, Char(1))));
}

// Tests using Invoke() with a 4-argument method.
TEST(InvokeMethodTest, MethodThatTakes4Arguments) {
  Foo foo;
  Action<int(int, int, int, int)> a = Invoke(&foo, &Foo::SumOf4);  // NOLINT
  EXPECT_EQ(1357, a.Perform(make_tuple(1000, 200, 30, 4)));
}

// Tests using Invoke() with a 5-argument method.
TEST(InvokeMethodTest, MethodThatTakes5Arguments) {
  Foo foo;
  Action<int(int, int, int, int, int)> a = Invoke(&foo, &Foo::SumOf5);  // NOLINT
  EXPECT_EQ(12345, a.Perform(make_tuple(10000, 2000, 300, 40, 5)));
}

// Tests using Invoke() with a 6-argument method.
TEST(InvokeMethodTest, MethodThatTakes6Arguments) {
  Foo foo;
  Action<int(int, int, int, int, int, int)> a =  // NOLINT
      Invoke(&foo, &Foo::SumOf6);
  EXPECT_EQ(123456, a.Perform(make_tuple(100000, 20000, 3000, 400, 50, 6)));
}

// Tests using Invoke() with a 7-argument method.
TEST(InvokeMethodTest, MethodThatTakes7Arguments) {
  Foo foo;
  Action<string(const char*, const char*, const char*, const char*,
                const char*, const char*, const char*)> a =
      Invoke(&foo, &Foo::Concat7);
  EXPECT_EQ("1234567",
            a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"),
                                 CharPtr("4"), CharPtr("5"), CharPtr("6"),
                                 CharPtr("7"))));
}

// Tests using Invoke() with a 8-argument method.
TEST(InvokeMethodTest, MethodThatTakes8Arguments) {
  Foo foo;
  Action<string(const char*, const char*, const char*, const char*,
                const char*, const char*, const char*, const char*)> a =
      Invoke(&foo, &Foo::Concat8);
  EXPECT_EQ("12345678",
            a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"),
                                 CharPtr("4"), CharPtr("5"), CharPtr("6"),
                                 CharPtr("7"), CharPtr("8"))));
}

// Tests using Invoke() with a 9-argument method.
TEST(InvokeMethodTest, MethodThatTakes9Arguments) {
  Foo foo;
  Action<string(const char*, const char*, const char*, const char*,
                const char*, const char*, const char*, const char*,
                const char*)> a = Invoke(&foo, &Foo::Concat9);
  EXPECT_EQ("123456789",
            a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"),
                                 CharPtr("4"), CharPtr("5"), CharPtr("6"),
                                 CharPtr("7"), CharPtr("8"), CharPtr("9"))));
}

// Tests using Invoke() with a 10-argument method.
TEST(InvokeMethodTest, MethodThatTakes10Arguments) {
  Foo foo;
  Action<string(const char*, const char*, const char*, const char*,
                const char*, const char*, const char*, const char*,
                const char*, const char*)> a = Invoke(&foo, &Foo::Concat10);
  EXPECT_EQ("1234567890",
            a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"),
                                 CharPtr("4"), CharPtr("5"), CharPtr("6"),
                                 CharPtr("7"), CharPtr("8"), CharPtr("9"),
                                 CharPtr("0"))));
}

// Tests using Invoke(f) as an action of a compatible type.
TEST(InvokeMethodTest, MethodWithCompatibleType) {
  Foo foo;
  Action<long(int, short, char, bool)> a =  // NOLINT
      Invoke(&foo, &Foo::SumOf4);
  EXPECT_EQ(4444, a.Perform(make_tuple(4000, Short(300), Char(20), true)));
}

// Tests using WithoutArgs with an action that takes no argument.
TEST(WithoutArgsTest, NoArg) {
  Action<int(int n)> a = WithoutArgs(Invoke(Nullary));  // NOLINT
  EXPECT_EQ(1, a.Perform(make_tuple(2)));
}

// Tests using WithArg with an action that takes 1 argument.
TEST(WithArgTest, OneArg) {
  Action<bool(double x, int n)> b = WithArg<1>(Invoke(Unary));  // NOLINT
  EXPECT_TRUE(b.Perform(make_tuple(1.5, -1)));
  EXPECT_FALSE(b.Perform(make_tuple(1.5, 1)));
}

TEST(ReturnArgActionTest, WorksForOneArgIntArg0) {
  const Action<int(int)> a = ReturnArg<0>();
  EXPECT_EQ(5, a.Perform(make_tuple(5)));
}

TEST(ReturnArgActionTest, WorksForMultiArgBoolArg0) {
  const Action<bool(bool, bool, bool)> a = ReturnArg<0>();
  EXPECT_TRUE(a.Perform(make_tuple(true, false, false)));
}

TEST(ReturnArgActionTest, WorksForMultiArgStringArg2) {
  const Action<string(int, int, string, int)> a = ReturnArg<2>();
  EXPECT_EQ("seven", a.Perform(make_tuple(5, 6, string("seven"), 8)));
}

TEST(SaveArgActionTest, WorksForSameType) {
  int result = 0;
  const Action<void(int n)> a1 = SaveArg<0>(&result);
  a1.Perform(make_tuple(5));
  EXPECT_EQ(5, result);
}

TEST(SaveArgActionTest, WorksForCompatibleType) {
  int result = 0;
  const Action<void(bool, char)> a1 = SaveArg<1>(&result);
  a1.Perform(make_tuple(true, 'a'));
  EXPECT_EQ('a', result);
}

TEST(SaveArgPointeeActionTest, WorksForSameType) {
  int result = 0;
  const int value = 5;
  const Action<void(const int*)> a1 = SaveArgPointee<0>(&result);
  a1.Perform(make_tuple(&value));
  EXPECT_EQ(5, result);
}

TEST(SaveArgPointeeActionTest, WorksForCompatibleType) {
  int result = 0;
  char value = 'a';
  const Action<void(bool, char*)> a1 = SaveArgPointee<1>(&result);
  a1.Perform(make_tuple(true, &value));
  EXPECT_EQ('a', result);
}

TEST(SaveArgPointeeActionTest, WorksForLinkedPtr) {
  int result = 0;
  linked_ptr<int> value(new int(5));
  const Action<void(linked_ptr<int>)> a1 = SaveArgPointee<0>(&result);
  a1.Perform(make_tuple(value));
  EXPECT_EQ(5, result);
}

TEST(SetArgRefereeActionTest, WorksForSameType) {
  int value = 0;
  const Action<void(int&)> a1 = SetArgReferee<0>(1);
  a1.Perform(tuple<int&>(value));
  EXPECT_EQ(1, value);
}

TEST(SetArgRefereeActionTest, WorksForCompatibleType) {
  int value = 0;
  const Action<void(int, int&)> a1 = SetArgReferee<1>('a');
  a1.Perform(tuple<int, int&>(0, value));
  EXPECT_EQ('a', value);
}

TEST(SetArgRefereeActionTest, WorksWithExtraArguments) {
  int value = 0;
  const Action<void(bool, int, int&, const char*)> a1 = SetArgReferee<2>('a');
  a1.Perform(tuple<bool, int, int&, const char*>(true, 0, value, "hi"));
  EXPECT_EQ('a', value);
}

// A class that can be used to verify that its destructor is called: it will set
// the bool provided to the constructor to true when destroyed.
class DeletionTester {
 public:
  explicit DeletionTester(bool* is_deleted)
    : is_deleted_(is_deleted) {
    // Make sure the bit is set to false.
    *is_deleted_ = false;
  }

  ~DeletionTester() {
    *is_deleted_ = true;
  }

 private:
  bool* is_deleted_;
};

TEST(DeleteArgActionTest, OneArg) {
  bool is_deleted = false;
  DeletionTester* t = new DeletionTester(&is_deleted);
  const Action<void(DeletionTester*)> a1 = DeleteArg<0>();      // NOLINT
  EXPECT_FALSE(is_deleted);
  a1.Perform(make_tuple(t));
  EXPECT_TRUE(is_deleted);
}

TEST(DeleteArgActionTest, TenArgs) {
  bool is_deleted = false;
  DeletionTester* t = new DeletionTester(&is_deleted);
  const Action<void(bool, int, int, const char*, bool,
                    int, int, int, int, DeletionTester*)> a1 = DeleteArg<9>();
  EXPECT_FALSE(is_deleted);
  a1.Perform(make_tuple(true, 5, 6, CharPtr("hi"), false, 7, 8, 9, 10, t));
  EXPECT_TRUE(is_deleted);
}

#if GTEST_HAS_EXCEPTIONS

TEST(ThrowActionTest, ThrowsGivenExceptionInVoidFunction) {
  const Action<void(int n)> a = Throw('a');
  EXPECT_THROW(a.Perform(make_tuple(0)), char);
}

class MyException {};

TEST(ThrowActionTest, ThrowsGivenExceptionInNonVoidFunction) {
  const Action<double(char ch)> a = Throw(MyException());
  EXPECT_THROW(a.Perform(make_tuple('0')), MyException);
}

TEST(ThrowActionTest, ThrowsGivenExceptionInNullaryFunction) {
  const Action<double()> a = Throw(MyException());
  EXPECT_THROW(a.Perform(make_tuple()), MyException);
}

#endif  // GTEST_HAS_EXCEPTIONS

// Tests that SetArrayArgument<N>(first, last) sets the elements of the array
// pointed to by the N-th (0-based) argument to values in range [first, last).
TEST(SetArrayArgumentTest, SetsTheNthArray) {
  typedef void MyFunction(bool, int*, char*);
  int numbers[] = { 1, 2, 3 };
  Action<MyFunction> a = SetArrayArgument<1>(numbers, numbers + 3);

  int n[4] = {};
  int* pn = n;
  char ch[4] = {};
  char* pch = ch;
  a.Perform(make_tuple(true, pn, pch));
  EXPECT_EQ(1, n[0]);
  EXPECT_EQ(2, n[1]);
  EXPECT_EQ(3, n[2]);
  EXPECT_EQ(0, n[3]);
  EXPECT_EQ('\0', ch[0]);
  EXPECT_EQ('\0', ch[1]);
  EXPECT_EQ('\0', ch[2]);
  EXPECT_EQ('\0', ch[3]);

  // Tests first and last are iterators.
  std::string letters = "abc";
  a = SetArrayArgument<2>(letters.begin(), letters.end());
  std::fill_n(n, 4, 0);
  std::fill_n(ch, 4, '\0');
  a.Perform(make_tuple(true, pn, pch));
  EXPECT_EQ(0, n[0]);
  EXPECT_EQ(0, n[1]);
  EXPECT_EQ(0, n[2]);
  EXPECT_EQ(0, n[3]);
  EXPECT_EQ('a', ch[0]);
  EXPECT_EQ('b', ch[1]);
  EXPECT_EQ('c', ch[2]);
  EXPECT_EQ('\0', ch[3]);
}

// Tests SetArrayArgument<N>(first, last) where first == last.
TEST(SetArrayArgumentTest, SetsTheNthArrayWithEmptyRange) {
  typedef void MyFunction(bool, int*);
  int numbers[] = { 1, 2, 3 };
  Action<MyFunction> a = SetArrayArgument<1>(numbers, numbers);

  int n[4] = {};
  int* pn = n;
  a.Perform(make_tuple(true, pn));
  EXPECT_EQ(0, n[0]);
  EXPECT_EQ(0, n[1]);
  EXPECT_EQ(0, n[2]);
  EXPECT_EQ(0, n[3]);
}

// Tests SetArrayArgument<N>(first, last) where *first is convertible
// (but not equal) to the argument type.
TEST(SetArrayArgumentTest, SetsTheNthArrayWithConvertibleType) {
  typedef void MyFunction(bool, int*);
  char chars[] = { 97, 98, 99 };
  Action<MyFunction> a = SetArrayArgument<1>(chars, chars + 3);

  int codes[4] = { 111, 222, 333, 444 };
  int* pcodes = codes;
  a.Perform(make_tuple(true, pcodes));
  EXPECT_EQ(97, codes[0]);
  EXPECT_EQ(98, codes[1]);
  EXPECT_EQ(99, codes[2]);
  EXPECT_EQ(444, codes[3]);
}

// Test SetArrayArgument<N>(first, last) with iterator as argument.
TEST(SetArrayArgumentTest, SetsTheNthArrayWithIteratorArgument) {
  typedef void MyFunction(bool, std::back_insert_iterator<std::string>);
  std::string letters = "abc";
  Action<MyFunction> a = SetArrayArgument<1>(letters.begin(), letters.end());

  std::string s;
  a.Perform(make_tuple(true, back_inserter(s)));
  EXPECT_EQ(letters, s);
}

TEST(ReturnPointeeTest, Works) {
  int n = 42;
  const Action<int()> a = ReturnPointee(&n);
  EXPECT_EQ(42, a.Perform(make_tuple()));

  n = 43;
  EXPECT_EQ(43, a.Perform(make_tuple()));
}

}  // namespace gmock_generated_actions_test
}  // namespace testing