From b45e563e54125125f459078b3694e6fd0ed17d64 Mon Sep 17 00:00:00 2001 From: EdFuentetaja Date: Tue, 6 May 2014 23:57:15 +0800 Subject: [PATCH 01/10] Fixed some compilation warnings and added a few comments. --- descramble.h | 13 +++++++++---- dsd.h | 5 +++++ dsd_dibit.c | 28 ++++++++++++++++++++++++---- dsd_filters.c | 2 +- dsd_frame.c | 6 +++--- dsd_frame_sync.c | 24 ++++++++++++------------ dsd_mbe.c | 3 +++ dsd_upsample.c | 6 +++--- 8 files changed, 60 insertions(+), 27 deletions(-) diff --git a/descramble.h b/descramble.h index c167f7b..6dbe4f1 100644 --- a/descramble.h +++ b/descramble.h @@ -166,16 +166,21 @@ void viterbiDecode (int n, int *data, int *m_pathMemory0, int *m_pathMemory1, in int FECdecoder (int * in, int * out) { int outLen; -int m_pathMemory0[330]; memset(m_pathMemory0,0,330*sizeof(int)); -int m_pathMemory1[330]; memset(m_pathMemory1,0,330*sizeof(int)); -int m_pathMemory2[330]; memset(m_pathMemory2,0,330*sizeof(int)); -int m_pathMemory3[330]; memset(m_pathMemory3,0,330*sizeof(int)); +int m_pathMemory0[330]; +int m_pathMemory1[330]; +int m_pathMemory2[330]; +int m_pathMemory3[330]; int m_pathMetric[4]; int loop,loop2; int n=0; +memset(m_pathMemory0,0,330*sizeof(int)); +memset(m_pathMemory1,0,330*sizeof(int)); +memset(m_pathMemory2,0,330*sizeof(int)); +memset(m_pathMemory3,0,330*sizeof(int)); + for (loop=0;loop<4;loop++) { m_pathMetric[loop]=0; }; // end for diff --git a/dsd.h b/dsd.h index ad6ffdc..b34f6fc 100644 --- a/dsd.h +++ b/dsd.h @@ -15,6 +15,9 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#ifndef DSD_H__f8398b5f0d5d49a1be2f1645325dfdb2 +#define DSD_H__f8398b5f0d5d49a1be2f1645325dfdb2 + #include "config.h" #include #include @@ -264,3 +267,5 @@ void processX2TDMAvoice (dsd_opts * opts, dsd_state * state); void processDSTAR_HD (dsd_opts * opts, dsd_state * state); short dmr_filter(short sample); short nxdn_filter(short sample); + +#endif // DSD_H__f8398b5f0d5d49a1be2f1645325dfdb2 diff --git a/dsd_dibit.c b/dsd_dibit.c index 3d05e4e..62bbd20 100644 --- a/dsd_dibit.c +++ b/dsd_dibit.c @@ -189,32 +189,43 @@ getDibit (dsd_opts * opts, dsd_state * state) { *state->dibit_buf_p = 1; state->dibit_buf_p++; - return (0); + return (0); // +1 } else { *state->dibit_buf_p = 3; state->dibit_buf_p++; - return (1); + return (1); // +3 } } else if ((state->synctype == 7) || (state->synctype == 15)|| (state->synctype == 19)) { + // 7 -D-STAR + // 15 -ProVoice + // 19 -D-STAR_HD + if (symbol > state->center) { *state->dibit_buf_p = 1; state->dibit_buf_p++; - return (1); + return (1); // +3 } else { *state->dibit_buf_p = 3; state->dibit_buf_p++; - return (0); + return (0); // +1 } } else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) || (state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13)) { + // 1 -P25p1 + // 3 -X2-TDMA (inverted signal voice frame) + // 5 -X2-TDMA (inverted signal data frame) + // 9 -NXDN (inverted voice frame) + // 11 -DMR (inverted signal voice frame) + // 13 -DMR (inverted signal data frame) + if (symbol > state->center) { if (symbol > state->umid) @@ -248,6 +259,15 @@ getDibit (dsd_opts * opts, dsd_state * state) } else { + // 0 +P25p1 + // 2 +X2-TDMA (non inverted signal data frame) + // 4 +X2-TDMA (non inverted signal voice frame) + // 8 +NXDN (non inverted voice frame) + // 10 +DMR (non inverted signal data frame) + // 12 +DMR (non inverted signal voice frame) + // 16 +NXDN (non inverted data frame) + // 17 -NXDN (inverted data frame) ??? + if (symbol > state->center) { if (symbol > state->umid) diff --git a/dsd_filters.c b/dsd_filters.c index aff98dd..672b25e 100644 --- a/dsd_filters.c +++ b/dsd_filters.c @@ -112,5 +112,5 @@ dsd_input_filter(short sample, int mode) for (i = 0; i <= zeros; i++) sum += (coeffs[i] * v[i]); - return sum / ngain; // filtered sample out + return (short)(sum / ngain); // filtered sample out } \ No newline at end of file diff --git a/dsd_frame.c b/dsd_frame.c index 21cd744..7b59728 100644 --- a/dsd_frame.c +++ b/dsd_frame.c @@ -54,7 +54,7 @@ processFrame (dsd_opts * opts, dsd_state * state) char nac[13]; int level; - char status_0, status_1; + char status_0; char bch_code[63]; int index_bch_code; unsigned char parity; @@ -69,8 +69,8 @@ processFrame (dsd_opts * opts, dsd_state * state) if (state->rf_mod == 1) { - state->maxref = (state->max * 0.80); - state->minref = (state->min * 0.80); + state->maxref = (int)(state->max * 0.80F); + state->minref = (int)(state->min * 0.80F); } else { diff --git a/dsd_frame_sync.c b/dsd_frame_sync.c index bf44760..1993c23 100644 --- a/dsd_frame_sync.c +++ b/dsd_frame_sync.c @@ -43,16 +43,16 @@ int getFrameSync (dsd_opts * opts, dsd_state * state) { /* detects frame sync and returns frame type - * 0 = +P25p1 - * 1 = -P25p1 - * 2 = +X2-TDMA (non inverted signal data frame) - * 3 = +X2-TDMA (inverted signal voice frame) - * 4 = -X2-TDMA (non inverted signal voice frame) - * 5 = -X2-TDMA (inverted signal data frame) - * 6 = +D-STAR - * 7 = -D-STAR - * 8 = +NXDN (non inverted voice frame) - * 9 = -NXDN (inverted voice frame) + * 0 = +P25p1 + * 1 = -P25p1 + * 2 = +X2-TDMA (non inverted signal data frame) + * 3 = -X2-TDMA (inverted signal voice frame) + * 4 = +X2-TDMA (non inverted signal voice frame) + * 5 = -X2-TDMA (inverted signal data frame) + * 6 = +D-STAR + * 7 = -D-STAR + * 8 = +NXDN (non inverted voice frame) + * 9 = -NXDN (inverted voice frame) * 10 = +DMR (non inverted signal data frame) * 11 = -DMR (inverted signal voice frame) * 12 = +DMR (non inverted signal voice frame) @@ -211,8 +211,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state) } state->max = lsum / opts->msize; state->center = ((state->max) + (state->min)) / 2; - state->maxref = ((state->max) * 0.80); - state->minref = ((state->min) * 0.80); + state->maxref = (int)((state->max) * 0.80F); + state->minref = (int)((state->min) * 0.80F); } else { diff --git a/dsd_mbe.c b/dsd_mbe.c index e0b7997..3e93a82 100644 --- a/dsd_mbe.c +++ b/dsd_mbe.c @@ -88,6 +88,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a if ((state->synctype == 0) || (state->synctype == 1)) { + // 0 +P25p1 + // 1 -P25p1 + mbe_processImbe7200x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); if (opts->mbe_out_f != NULL) { diff --git a/dsd_upsample.c b/dsd_upsample.c index 3bbc584..42623f4 100644 --- a/dsd_upsample.c +++ b/dsd_upsample.c @@ -53,11 +53,11 @@ upsample (dsd_state * state, float invalue) { sum = 0; outbuf1 -= 2; - sum += *outbuf1; + sum += (int)*outbuf1; outbuf1 += 2; - sum += *outbuf1; + sum += (int)*outbuf1; outbuf1 += 2; - sum += *outbuf1; + sum += (int)*outbuf1; outbuf1 -= 2; *outbuf1 = (sum / (float) 3); outbuf1++; From 9d0fe0793188802441c5bc88e89a14e8cff732ff Mon Sep 17 00:00:00 2001 From: EdFuentetaja Date: Sun, 11 May 2014 02:23:24 +0800 Subject: [PATCH 02/10] Included error correction on P25 TDULC. Added a new "heuristics" module for P25 that improves the estimation of the symbol (dibit) that corresponds to a given analog signal value. Added a BER (bit error reate) estimation for P25. --- Golay24.hpp | 131 +++++++++-- Hamming.cpp | 23 +- Hamming.hpp | 159 ++++++++++++- ReedSolomon.hpp | 229 +++++++++++------- dsd.h | 29 ++- dsd_audio.c | 95 ++++---- dsd_dibit.c | 418 +++++++++++++++++++++------------ dsd_frame.c | 5 +- dsd_main.c | 43 +++- dsd_symbol.c | 94 +++++++- fcs.h | 4 +- p25p1_check_hdu.cpp | 76 +++++- p25p1_check_hdu.h | 45 +++- p25p1_check_ldu.cpp | 39 +++- p25p1_check_ldu.h | 42 +++- p25p1_check_nid.cpp | 3 +- p25p1_check_nid.h | 14 +- p25p1_hdu.c | 471 ++++++++++++++++++++++++------------- p25p1_hdu.h | 72 +++++- p25p1_heuristics.c | 386 ++++++++++++++++++++++++++++++ p25p1_heuristics.h | 91 ++++++++ p25p1_ldu.c | 234 ++++++++++++++++--- p25p1_ldu.h | 51 +++- p25p1_ldu1.c | 151 ++++++++---- p25p1_ldu2.c | 154 ++++++++---- p25p1_tdu.c | 34 +++ p25p1_tdulc.c | 479 ++++++++++++++++++++++++++++---------- test/golay24-test.cpp | 40 +++- test/hamming-test.cpp | 115 ++++++--- test/reedsolomon-test.cpp | 77 +++++- 30 files changed, 2976 insertions(+), 828 deletions(-) create mode 100644 p25p1_heuristics.c create mode 100644 p25p1_heuristics.h create mode 100644 p25p1_tdu.c diff --git a/Golay24.hpp b/Golay24.hpp index 89f9a47..0731024 100644 --- a/Golay24.hpp +++ b/Golay24.hpp @@ -1,3 +1,7 @@ + +#ifndef GOLAY24_HPP_7a68240afda9406facf81fcad3851111 +#define GOLAY24_HPP_7a68240afda9406facf81fcad3851111 + /** * Based on the work of Mr Hank Wallace. * @@ -8,7 +12,7 @@ */ #include - +#include #define POLY 0xAE3 @@ -129,7 +133,7 @@ private: } public: - unsigned int correct(unsigned int cw, int *errs) + unsigned int correct(unsigned int cw, int *errs, unsigned int *errors_detected) /* This function corrects Golay [23,12] codeword cw, returning the corrected codeword. This function will produce the corrected codeword for three or fewer errors. It will produce some other valid Golay @@ -148,6 +152,8 @@ public: cwsaver=cw; /* save */ *errs=0; + *errors_detected = 0; + w=3; /* initial syndrome weight threshold */ j=-1; /* -1 = no trial bit flipping on first pass */ mask=1; @@ -167,6 +173,7 @@ public: s=syndrome(cw); /* look for errors */ if (s) /* errors exist */ { + (*errors_detected)++; for (i=0; i<23; i++) /* check syndrome of each cyclic shift */ { if ((*errs=weight(s)) <= w) /* syndrome matches error pattern */ @@ -184,7 +191,9 @@ public: j++; /* toggle next trial bit */ } else - return(cw); /* return corrected codeword */ + { + return(cw); /* return corrected codeword */ + } } return(cwsaver); /* return original if no corrections */ @@ -200,6 +209,11 @@ public: return codeword; } + unsigned int encode23(unsigned int data) + { + return golay(data); /* make a test codeword */ + } + int decode(int *errs, unsigned int *cw) /* This function decodes codeword *cw. Here error correction is attempted, with *errs set to the number of @@ -207,11 +221,11 @@ public: exist. */ { unsigned int parity_bit; - + unsigned int detected_errors; parity_bit=*cw & 0x800000l; /* save parity bit */ *cw&=~0x800000l; /* remove parity bit for correction */ - *cw=correct(*cw, errs); /* correct up to three bits */ + *cw=correct(*cw, errs, &detected_errors); /* correct up to three bits */ *cw|=parity_bit; /* restore parity bit */ /* check for 4 bit errors */ @@ -226,8 +240,6 @@ public: returning 0 if no errors exist, 1 if an overall parity error exists, and 2 if a codeword error exists. */ { - unsigned int parity_bit; - *errs=0; if (parity(cw)) /* odd parity is an error */ { @@ -254,34 +266,59 @@ public: class DSDGolay24 : public Golay24 { public: - unsigned int adapt_to_codeword(const char* hex, const char* parity) + unsigned int adapt_to_codeword(const char* word, unsigned int length, const char* parity) { unsigned int codeword = 0; // Data needs to be packed with the 12 bits of parity as the most significant // bits and 12 bits of data as the less significant. All these discovered by trial and error. for (unsigned int i=0; i<12; i++) { + assert(parity[11-i] == 0 || parity[11-i] == 1); + codeword <<= 1; codeword |= parity[11-i]; - codeword <<= 1; } - for (unsigned int i=0; i<6; i++) { - codeword |= hex[5-i]; + for (unsigned int i=0; i +#include "Hamming.hpp" // definition outside class declaration Hamming_10_6_3_data Hamming_10_6_3::data; @@ -50,6 +50,18 @@ int Hamming_10_6_3::decode(std::bitset<10>& input) return error_count; } +int Hamming_10_6_3::encode(std::bitset<6>& input) +{ + // Compute syndromes + int s0 = ((data.gt0 & input).count() & 1) << 3; + int s1 = ((data.gt1 & input).count() & 1) << 2; + int s2 = ((data.gt2 & input).count() & 1) << 1; + int s3 = ((data.gt3 & input).count() & 1); + int parity = s0 | s1 | s2 | s3; + + return parity; +} + int Hamming_10_6_3_TableImpl::decode(int input, int* output) { assert (input < 1024 && input >= 0); @@ -60,3 +72,12 @@ int Hamming_10_6_3_TableImpl::decode(int input, int* output) return data.error_counts[input]; } + +int Hamming_10_6_3_TableImpl::encode(int input) +{ + assert (input < 64 && input >= 0); + + // Making use of a table... + + return data.encode_parities[input]; +} diff --git a/Hamming.hpp b/Hamming.hpp index e64ec6d..b0a0be1 100644 --- a/Hamming.hpp +++ b/Hamming.hpp @@ -1,6 +1,6 @@ -#ifndef __HAMMING_HPP__ -#define __HAMMING_HPP__ +#ifndef HAMMING_HPP_e7123c3795b94d14b5774d5d8f016a04 +#define HAMMING_HPP_e7123c3795b94d14b5774d5d8f016a04 #include #include @@ -22,6 +22,11 @@ public: std::bitset<10> g4; std::bitset<10> g5; + std::bitset<6> gt0; + std::bitset<6> gt1; + std::bitset<6> gt2; + std::bitset<6> gt3; + std::bitset<10> h0; std::bitset<10> h1; std::bitset<10> h2; @@ -39,6 +44,11 @@ public: g4 = std::bitset<10>(std::string("0000100011")); g5 = std::bitset<10>(std::string("0000011100")); + gt0 = std::bitset<6>(std::string("111001")); + gt1 = std::bitset<6>(std::string("110101")); + gt2 = std::bitset<6>(std::string("101110")); + gt3 = std::bitset<6>(std::string("011110")); + // H matrix, calculated transposing G. See wikipedia. h0 = std::bitset<10>(std::string("1110011000")); h1 = std::bitset<10>(std::string("1101010100")); @@ -74,6 +84,89 @@ public: } }; +class Hamming_15_11_3_data +{ +public: + std::bitset<15> g0; + std::bitset<15> g1; + std::bitset<15> g2; + std::bitset<15> g3; + std::bitset<15> g4; + std::bitset<15> g5; + std::bitset<15> g6; + std::bitset<15> g7; + std::bitset<15> g8; + std::bitset<15> g9; + std::bitset<15> g10; + + + std::bitset<11> gt0; + std::bitset<11> gt1; + std::bitset<11> gt2; + std::bitset<11> gt3; + + std::bitset<15> h0; + std::bitset<15> h1; + std::bitset<15> h2; + std::bitset<15> h3; + + int bad_bit_table[16]; + + Hamming_15_11_3_data() + { + // G matrix come from the APCO 25 reference documentation: + g0 = std::bitset<15>(std::string("100000000001111")); + g1 = std::bitset<15>(std::string("010000000001110")); + g2 = std::bitset<15>(std::string("001000000001101")); + g3 = std::bitset<15>(std::string("000100000001100")); + g4 = std::bitset<15>(std::string("000010000001011")); + g5 = std::bitset<15>(std::string("000001000001010")); + g6 = std::bitset<15>(std::string("000000100001001")); + g7 = std::bitset<15>(std::string("000000010000111")); + g8 = std::bitset<15>(std::string("000000001000110")); + g9 = std::bitset<15>(std::string("000000000100101")); + g10 = std::bitset<15>(std::string("000000000010011")); + + gt0 = std::bitset<11>(std::string("11111110000")); + gt1 = std::bitset<11>(std::string("11110001110")); + gt2 = std::bitset<11>(std::string("11001101101")); + gt3 = std::bitset<11>(std::string("10101011011")); + + // H matrix, calculated transposing G. See wikipedia. + h0 = std::bitset<15>(std::string("111111100001000")); + h1 = std::bitset<15>(std::string("111100011100100")); + h2 = std::bitset<15>(std::string("110011011010010")); + h3 = std::bitset<15>(std::string("101010110110001")); + + // bad_bit_table indicates which is the bit to correct from the calculated syndromes. + // It's calculated from the previous matrices: See the left-most column of the matrix whose rows are + // h0,h1,h2 and h3. It's [1 1 1 0]. It means: when the syndrome value is the binary number 1110, the + // bit that is wrong is the bit 9 (the left-most column is for the bit 9). Another example with + // the right-most column: it's column is [0 0 0 1], so when the syndrome is 0001, the bit to fix is + // bit 0 (one of the parity bits). + bad_bit_table[ 1] = 0; + bad_bit_table[ 2] = 1; + bad_bit_table[ 4] = 2; + bad_bit_table[ 8] = 3; + bad_bit_table[12] = 4; + bad_bit_table[ 3] = 5; + bad_bit_table[ 7] = 6; + bad_bit_table[11] = 7; + bad_bit_table[13] = 8; + bad_bit_table[14] = 9; + + // If the syndrome is zero, then the data is correct, no errors detected. + bad_bit_table[ 0] = -2; + + // Incorrect values, if the syndrome gets one of this values, then we fail to correct the data. + bad_bit_table[ 5] = -1; + bad_bit_table[ 6] = -1; + bad_bit_table[ 9] = -1; + bad_bit_table[10] = -1; + bad_bit_table[15] = -1; + } +}; + /** * An interface used by the two implementations defined here. */ @@ -101,6 +194,10 @@ public: * \return Count of detected errors. */ virtual int decode(char* hex, char* parity) = 0; + + virtual int encode(int input) = 0; + + virtual void encode(char* hex, char* out_parity) = 0; }; /** @@ -145,10 +242,10 @@ public: std::bitset<10> value; // in the bitset 9 is the left-most and 0 is the right-most for (unsigned int i=0; i<6; i++) { - value[9-i] = hex[i]; + value[9-i] = (hex[i] == 1)? true : false; } for (unsigned int i=0; i<4; i++) { - value[3-i] = parity[i]; + value[3-i] = (parity[i] == 1)? true : false; } int error_count = decode(value); @@ -164,6 +261,35 @@ public: return error_count; } + + int encode(std::bitset<6>& input); + + int encode(int input) + { + assert (input < 64 && input >= 0); + + std::bitset<6> bitset_input(input); + + return encode(bitset_input); + } + + void encode(char* hex, char* out_parity) + { + // Make a bitset from hex + std::bitset<6> value; + // in the bitset 5 is the left-most and 0 is the right-most + for (unsigned int i=0; i<6; i++) { + value[5-i] = (hex[i] == 1)? true : false; + } + + int parity = encode(value); + + // Put the calculated parity in the form of a char array + for (int i=3; i>=0; i--) { + out_parity[i] = parity & 1; + parity >>= 1; + } + } }; /** @@ -174,6 +300,7 @@ class Hamming_10_6_3_TableImpl_data public: int fixed_values[1024]; int error_counts[1024]; + int encode_parities[64]; /** * \brief On initialization it builds a table to calculate every possible outcome (there are 1024) before @@ -190,6 +317,11 @@ public: fixed_values[i] = fixed; error_counts[i] = error_count; } + + for (int i=0; i<64; i++) { + int parity = hamming.encode(i); + encode_parities[i] = parity; + } } }; @@ -210,6 +342,7 @@ public: int value = 0; // in the bitset 9 is the left-most and 0 is the right-most for (unsigned int i=0; i<6; i++) { + assert(hex[i] == 0 || hex[i] == 1); value <<= 1; value |= hex[i]; } @@ -223,10 +356,12 @@ public: int value = 0; // in the bitset 9 is the left-most and 0 is the right-most for (unsigned int i=0; i<6; i++) { + assert(hex[i] == 0 || hex[i] == 1); value <<= 1; value |= hex[i]; } for (unsigned int i=0; i<4; i++) { + assert(parity[i] == 0 || parity[i] == 1); value <<= 1; value |= parity[i]; } @@ -258,7 +393,21 @@ public: return error_count; } + + int encode(int input); + + void encode(char* hex, char* out_parity) + { + int value = convert_hex_to_int(hex); + int parity = encode(value); + + // Put the calculated parity in the form of a char array + for (int i=3; i>=0; i--) { + out_parity[i] = parity & 1; + parity >>= 1; + } + } }; -#endif // __HAMMING_HPP__ +#endif // HAMMING_HPP_e7123c3795b94d14b5774d5d8f016a04 diff --git a/ReedSolomon.hpp b/ReedSolomon.hpp index 021e34f..49fbecc 100644 --- a/ReedSolomon.hpp +++ b/ReedSolomon.hpp @@ -1,5 +1,6 @@ -#ifndef __REED_SOLOMON_HPP__ -#define __REED_SOLOMON_HPP__ + +#ifndef REEDSOLOMON_HPP_b1405fdab6374ba2a4e65e8d45ec3d80 +#define REEDSOLOMON_HPP_b1405fdab6374ba2a4e65e8d45ec3d80 /** * Code taken and adapted from www.eccpage.com/rs.c @@ -59,15 +60,15 @@ #include #include -// Constants to adapt the code to DSD/P25 needs - +template class ReedSolomon_63 { private: - static const int mm = 6; /* RS code over GF(2**mm) */ - static const int nn = 63; /* nn=2**mm -1 length of codeword */ - int tt; /* number of errors that can be corrected */ - int kk; /* kk = nn-2*tt */ + static const int MM = 6; /* RS code over GF(2**mm) */ + static const int NN = 63; /* nn=2**mm -1 length of codeword */ + //int tt; /* number of errors that can be corrected */ + //int kk; /* kk = nn-2*tt */ + static const int KK = NN-2*TT; // distance = nn-kk+1 = 2*tt+1 int* alpha_to; @@ -84,19 +85,19 @@ private: register int i, mask; mask = 1; - alpha_to[mm] = 0; - for (i = 0; i < mm; i++) { + alpha_to[MM] = 0; + for (i = 0; i < MM; i++) { alpha_to[i] = mask; index_of[alpha_to[i]] = i; if (generator_polinomial[i] != 0) - alpha_to[mm] ^= mask; + alpha_to[MM] ^= mask; mask <<= 1; } - index_of[alpha_to[mm]] = mm; + index_of[alpha_to[MM]] = MM; mask >>= 1; - for (i = mm + 1; i < nn; i++) { + for (i = MM + 1; i < NN; i++) { if (alpha_to[i - 1] >= mask) - alpha_to[i] = alpha_to[mm] ^ ((alpha_to[i - 1] ^ mask) << 1); + alpha_to[i] = alpha_to[MM] ^ ((alpha_to[i - 1] ^ mask) << 1); else alpha_to[i] = alpha_to[i - 1] << 1; index_of[alpha_to[i]] = i; @@ -113,29 +114,26 @@ private: gg[0] = 2; /* primitive element alpha = 2 for GF(2**mm) */ gg[1] = 1; /* g(x) = (X+alpha) initially */ - for (i = 2; i <= nn - kk; i++) { + for (i = 2; i <= NN - KK; i++) { gg[i] = 1; for (j = i - 1; j > 0; j--) if (gg[j] != 0) - gg[j] = gg[j - 1] ^ alpha_to[(index_of[gg[j]] + i) % nn]; + gg[j] = gg[j - 1] ^ alpha_to[(index_of[gg[j]] + i) % NN]; else gg[j] = gg[j - 1]; - gg[0] = alpha_to[(index_of[gg[0]] + i) % nn]; /* gg[0] can never be zero */ + gg[0] = alpha_to[(index_of[gg[0]] + i) % NN]; /* gg[0] can never be zero */ } /* convert gg[] to index form for quicker encoding */ - for (i = 0; i <= nn - kk; i++) + for (i = 0; i <= NN - KK; i++) gg[i] = index_of[gg[i]]; } public: - ReedSolomon_63(int a_tt) + ReedSolomon_63() { - tt = a_tt; /* number of errors that can be corrected */ - kk = nn-2*tt; - - alpha_to = new int[nn + 1]; - index_of = new int[nn + 1]; - gg = new int[nn - kk + 1]; + alpha_to = new int[NN + 1]; + index_of = new int[NN + 1]; + gg = new int[NN - KK + 1]; // Polynom used in P25 is alpha**6+alpha+1 int generator_polinomial[] = { 1, 1, 0, 0, 0, 0, 1 }; /* specify irreducible polynomial coeffts */ @@ -152,7 +150,7 @@ public: delete[] alpha_to; } - void encode(int* data, int* bb) + void encode(const int* data, int* bb) /* take the string of symbols in data[i], i=0..(k-1) and encode systematically to produce 2*tt parity symbols in bb[0]..bb[2*tt-1] data[] is input and bb[] is output in polynomial form. @@ -163,19 +161,19 @@ public: register int i, j; int feedback; - for (i = 0; i < nn - kk; i++) + for (i = 0; i < NN - KK; i++) bb[i] = 0; - for (i = kk - 1; i >= 0; i--) { - feedback = index_of[data[i] ^ bb[nn - kk - 1]]; + for (i = KK - 1; i >= 0; i--) { + feedback = index_of[data[i] ^ bb[NN - KK - 1]]; if (feedback != -1) { - for (j = nn - kk - 1; j > 0; j--) + for (j = NN - KK - 1; j > 0; j--) if (gg[j] != -1) - bb[j] = bb[j - 1] ^ alpha_to[(gg[j] + feedback) % nn]; + bb[j] = bb[j - 1] ^ alpha_to[(gg[j] + feedback) % NN]; else bb[j] = bb[j - 1]; - bb[0] = alpha_to[(gg[0] + feedback) % nn]; + bb[0] = alpha_to[(gg[0] + feedback) % NN]; } else { - for (j = nn - kk - 1; j > 0; j--) + for (j = NN - KK - 1; j > 0; j--) bb[j] = bb[j - 1]; bb[0] = 0; } @@ -203,22 +201,22 @@ public: can be returned as error flags to the calling routine if desired. */ { register int i, j, u, q; - int elp[nn - kk + 2][nn - kk], d[nn - kk + 2], l[nn - kk + 2], u_lu[nn - kk - + 2], s[nn - kk + 1]; - int count = 0, syn_error = 0, root[tt], loc[tt], z[tt + 1], err[nn], reg[tt + int elp[NN - KK + 2][NN - KK], d[NN - KK + 2], l[NN - KK + 2], u_lu[NN - KK + + 2], s[NN - KK + 1]; + int count = 0, syn_error = 0, root[TT], loc[TT], z[TT + 1], err[NN], reg[TT + 1]; int irrecoverable_error = 0; - for (int i = 0; i < nn; i++) + for (int i = 0; i < NN; i++) recd[i] = index_of[input[i]]; /* put recd[i] into index form (ie as powers of alpha) */ /* first form the syndromes */ - for (i = 1; i <= nn - kk; i++) { + for (i = 1; i <= NN - KK; i++) { s[i] = 0; - for (j = 0; j < nn; j++) + for (j = 0; j < NN; j++) if (recd[j] != -1) - s[i] ^= alpha_to[(recd[j] + i * j) % nn]; /* recd[j] in index form */ + s[i] ^= alpha_to[(recd[j] + i * j) % NN]; /* recd[j] in index form */ /* convert syndrome from polynomial form to index form */ if (s[i] != 0) syn_error = 1; /* set flag if non-zero syndrome => error */ @@ -239,7 +237,7 @@ public: d[1] = s[1]; /* index form */ elp[0][0] = 0; /* index form */ elp[1][0] = 1; /* polynomial form */ - for (i = 1; i < nn - kk; i++) { + for (i = 1; i < NN - KK; i++) { elp[0][i] = -1; /* index form */ elp[1][i] = 0; /* polynomial form */ } @@ -281,12 +279,12 @@ public: l[u + 1] = l[q] + u - q; /* form new elp(x) */ - for (i = 0; i < nn - kk; i++) + for (i = 0; i < NN - KK; i++) elp[u + 1][i] = 0; for (i = 0; i <= l[q]; i++) if (elp[q][i] != -1) - elp[u + 1][i + u - q] = alpha_to[(d[u] + nn - d[q] - + elp[q][i]) % nn]; + elp[u + 1][i + u - q] = alpha_to[(d[u] + NN - d[q] + + elp[q][i]) % NN]; for (i = 0; i <= l[u]; i++) { elp[u + 1][i] ^= elp[u][i]; elp[u][i] = index_of[elp[u][i]]; /*convert old elp value to index*/ @@ -295,7 +293,7 @@ public: u_lu[u + 1] = u - l[u + 1]; /* form (u+1)th discrepancy */ - if (u < nn - kk) /* no discrepancy computed on last iteration */ + if (u < NN - KK) /* no discrepancy computed on last iteration */ { if (s[u + 1] != -1) d[u + 1] = alpha_to[s[u + 1]]; @@ -304,13 +302,13 @@ public: for (i = 1; i <= l[u + 1]; i++) if ((s[u + 1 - i] != -1) && (elp[u + 1][i] != 0)) d[u + 1] ^= alpha_to[(s[u + 1 - i] - + index_of[elp[u + 1][i]]) % nn]; + + index_of[elp[u + 1][i]]) % NN]; d[u + 1] = index_of[d[u + 1]]; /* put d[u+1] into index form */ } - } while ((u < nn - kk) && (l[u + 1] <= tt)); + } while ((u < NN - KK) && (l[u + 1] <= TT)); u++; - if (l[u] <= tt) /* can correct error */ + if (l[u] <= TT) /* can correct error */ { /* put elp into index form */ for (i = 0; i <= l[u]; i++) @@ -320,17 +318,17 @@ public: for (i = 1; i <= l[u]; i++) reg[i] = elp[u][i]; count = 0; - for (i = 1; i <= nn; i++) { + for (i = 1; i <= NN; i++) { q = 1; for (j = 1; j <= l[u]; j++) if (reg[j] != -1) { - reg[j] = (reg[j] + j) % nn; + reg[j] = (reg[j] + j) % NN; q ^= alpha_to[reg[j]]; }; if (!q) /* store root and error location number indices */ { root[count] = i; - loc[count] = nn - i; + loc[count] = NN - i; count++; }; }; @@ -350,12 +348,12 @@ public: z[i] = 0; for (j = 1; j < i; j++) if ((s[j] != -1) && (elp[u][i - j] != -1)) - z[i] ^= alpha_to[(elp[u][i - j] + s[j]) % nn]; + z[i] ^= alpha_to[(elp[u][i - j] + s[j]) % NN]; z[i] = index_of[z[i]]; /* put into index form */ }; /* evaluate errors at locations given by error location numbers loc[i] */ - for (i = 0; i < nn; i++) { + for (i = 0; i < NN; i++) { err[i] = 0; if (recd[i] != -1) /* convert recd[] to polynomial form */ recd[i] = alpha_to[recd[i]]; @@ -367,16 +365,16 @@ public: err[loc[i]] = 1; /* accounts for z[0] */ for (j = 1; j <= l[u]; j++) if (z[j] != -1) - err[loc[i]] ^= alpha_to[(z[j] + j * root[i]) % nn]; + err[loc[i]] ^= alpha_to[(z[j] + j * root[i]) % NN]; if (err[loc[i]] != 0) { err[loc[i]] = index_of[err[loc[i]]]; q = 0; /* form denominator of error term */ for (j = 0; j < l[u]; j++) if (j != i) q += index_of[1 - ^ alpha_to[(loc[j] + root[i]) % nn]]; - q = q % nn; - err[loc[i]] = alpha_to[(err[loc[i]] - q + nn) % nn]; + ^ alpha_to[(loc[j] + root[i]) % NN]]; + q = q % NN; + err[loc[i]] = alpha_to[(err[loc[i]] - q + NN) % NN]; recd[loc[i]] ^= err[loc[i]]; /*recd[i] must be in polynomial form */ } } @@ -392,7 +390,7 @@ public: } else { /* no non-zero syndromes => no errors: output received codeword */ - for (i = 0; i < nn; i++) + for (i = 0; i < NN; i++) if (recd[i] != -1) /* convert recd[] to polynomial form */ recd[i] = alpha_to[recd[i]]; else @@ -400,7 +398,7 @@ public: } if (irrecoverable_error) { - for (i = 0; i < nn; i++) /* could return error flag if desired */ + for (i = 0; i < NN; i++) /* could return error flag if desired */ if (recd[i] != -1) /* convert recd[] to polynomial form */ recd[i] = alpha_to[recd[i]]; else @@ -411,7 +409,7 @@ public: } protected: - int bin_to_hex(char* input) + int bin_to_hex(const char* input) { int output = ((input[0] != 0)? 32 : 0) | ((input[1] != 0)? 16 : 0) | @@ -438,12 +436,12 @@ protected: * Convenience class that does a Reed-Solomon (36,20,17) error correction adapting input and output to * the DSD data format: hex words packed as char arrays. */ -class DSDReedSolomon_36_20_17 : public ReedSolomon_63 +class DSDReedSolomon_36_20_17 : public ReedSolomon_63<8> { public: // tt = (dd-1)/2 // dd = 17 --> tt = 8 - DSDReedSolomon_36_20_17() : ReedSolomon_63(8) + DSDReedSolomon_36_20_17() : ReedSolomon_63<8>() { // Does nothing } @@ -451,11 +449,11 @@ public: /** * Does a Reed-Solomon decode adapting the input and output to the expected DSD data format. * \param hex_data Data packed bits, originally a char[20][6], so containing 20 hex works, each char - * is a bit. + * is a bit. Bits are corrected in place. * \param hex_parity Parity packed bits, originally a char[16][6], 16 hex words. * \return 1 if irrecoverable errors have been detected, 0 otherwise. */ - int decode(char* hex_data, char* hex_parity) + int decode(char* hex_data, const char* hex_parity) { int input[63]; int output[63]; @@ -476,7 +474,7 @@ public: } // Now we can call decode on the base class - int irrecoverable_errors = ReedSolomon_63::decode(input, output); + int irrecoverable_errors = ReedSolomon_63<8>::decode(input, output); // Convert it back to binary and put it into hex_data. If decode failed we should have // the input unchanged. @@ -486,18 +484,42 @@ public: return irrecoverable_errors; } + + void encode(const char* hex_data, char* out_hex_parity) + { + int input[47]; + int output[63]; + + // Put the 20 hex words of data + for(unsigned int i=0; i<20; i++) { + input[i] = bin_to_hex(hex_data + i*6); + } + + // Fill up with zeros to complete the 47 expected hex words of data + for(unsigned int i=20; i<47; i++) { + input[i] = 0; + } + + // Now we can call encode on the base class + ReedSolomon_63<8>::encode(input, output); + + // Convert it back to binary form and put it into the parity + for(unsigned int i=0; i<16; i++) { + hex_to_bin(output[i], out_hex_parity + i*6); + } + } }; /** * Convenience class that does a Reed-Solomon (24,12,13) error correction adapting input and output to * the DSD data format: hex words packed as char arrays. */ -class DSDReedSolomon_24_12_13 : public ReedSolomon_63 +class DSDReedSolomon_24_12_13 : public ReedSolomon_63<6> { public: // tt = (dd-1)/2 // dd = 13 --> tt = 6 - DSDReedSolomon_24_12_13() : ReedSolomon_63(6) + DSDReedSolomon_24_12_13() : ReedSolomon_63<6>() { // Does nothing } @@ -505,11 +527,11 @@ public: /** * Does a Reed-Solomon decode adapting the input and output to the expected DSD data format. * \param hex_data Data packed bits, originally a char[12][6], so containing 12 hex works, each char - * is a bit. + * is a bit. Bits are corrected in place. * \param hex_parity Parity packed bits, originally a char[12][6], 12 hex words. * \return 1 if irrecoverable errors have been detected, 0 otherwise. */ - int decode(char* hex_data, char* hex_parity) + int decode(char* hex_data, const char* hex_parity) { int input[63]; int output[63]; @@ -530,7 +552,7 @@ public: } // Now we can call decode on the base class - int irrecoverable_errors = ReedSolomon_63::decode(input, output); + int irrecoverable_errors = ReedSolomon_63<6>::decode(input, output); // Convert it back to binary and put it into hex_data. If decode failed we should have // the input unchanged. @@ -540,18 +562,43 @@ public: return irrecoverable_errors; } + + void encode(const char* hex_data, char* out_hex_parity) + { + int input[51]; + int output[63]; + + // Put the 12 hex words of data + for(unsigned int i=0; i<12; i++) { + input[i] = bin_to_hex(hex_data + i*6); + } + + // Fill up with zeros to complete the 51 expected hex words of data + for(unsigned int i=12; i<51; i++) { + input[i] = 0; + } + + // Now we can call encode on the base class + ReedSolomon_63<6>::encode(input, output); + + // Convert it back to binary form and put it into the parity + for(unsigned int i=0; i<12; i++) { + hex_to_bin(output[i], out_hex_parity + i*6); + } + } + }; /** * Convenience class that does a Reed-Solomon (24,16,9) error correction adapting input and output to * the DSD data format: hex words packed as char arrays. */ -class DSDReedSolomon_24_16_9 : public ReedSolomon_63 +class DSDReedSolomon_24_16_9 : public ReedSolomon_63<4> { public: // tt = (dd-1)/2 // dd = 9 --> tt = 4 - DSDReedSolomon_24_16_9() : ReedSolomon_63(4) + DSDReedSolomon_24_16_9() : ReedSolomon_63<4>() { // Does nothing } @@ -559,11 +606,11 @@ public: /** * Does a Reed-Solomon decode adapting the input and output to the expected DSD data format. * \param hex_data Data packed bits, originally a char[16][6], so containing 16 hex works, each char - * is a bit. + * is a bit. Bits are corrected in place. * \param hex_parity Parity packed bits, originally a char[8][6], 8 hex words. * \return 1 if irrecoverable errors have been detected, 0 otherwise. */ - int decode(char* hex_data, char* hex_parity) + int decode(char* hex_data, const char* hex_parity) { int input[63]; int output[63]; @@ -574,26 +621,50 @@ public: } // Then the 16 hex words of data - for(unsigned int i=8; i<8+12; i++) { + for(unsigned int i=8; i<8+16; i++) { input[i] = bin_to_hex(hex_data + (i-8)*6); } // Fill up with zeros to complete the 55 expected hex words of data - for(unsigned int i=8+12; i<63; i++) { + for(unsigned int i=8+16; i<63; i++) { input[i] = 0; } // Now we can call decode on the base class - int irrecoverable_errors = ReedSolomon_63::decode(input, output); + int irrecoverable_errors = ReedSolomon_63<4>::decode(input, output); // Convert it back to binary and put it into hex_data. If decode failed we should have // the input unchanged. - for(unsigned int i=8; i<8+12; i++) { + for(unsigned int i=8; i<8+16; i++) { hex_to_bin(output[i], hex_data + (i-8)*6); } return irrecoverable_errors; } + + void encode(const char* hex_data, char* out_hex_parity) + { + int input[55]; + int output[63]; + + // Put the 16 hex words of data + for(unsigned int i=0; i<16; i++) { + input[i] = bin_to_hex(hex_data + i*6); + } + + // Fill up with zeros to complete the 55 expected hex words of data + for(unsigned int i=16; i<55; i++) { + input[i] = 0; + } + + // Now we can call encode on the base class + ReedSolomon_63<4>::encode(input, output); + + // Convert it back to binary form and put it into the parity + for(unsigned int i=0; i<8; i++) { + hex_to_bin(output[i], out_hex_parity + i*6); + } + } }; -#endif // __REED_SOLOMON_HPP__ +#endif // REEDSOLOMON_HPP_b1405fdab6374ba2a4e65e8d45ec3d80 diff --git a/dsd.h b/dsd.h index b34f6fc..1accef7 100644 --- a/dsd.h +++ b/dsd.h @@ -40,6 +40,9 @@ #include #include #include + +#include "p25p1_heuristics.h" + /* * global variables */ @@ -176,6 +179,26 @@ typedef struct unsigned int debug_header_errors; unsigned int debug_header_critical_errors; + // Last dibit read + int last_dibit; + + // Heuristics state data for +P5 signals + P25Heuristics p25_heuristics; + + // Heuristics state data for -P5 signals + P25Heuristics inv_p25_heuristics; + +#ifdef TRACE_DSD + char debug_prefix; + char debug_prefix_2; + unsigned int debug_sample_index; + unsigned int debug_sample_left_edge; + unsigned int debug_sample_right_edge; + FILE* debug_label_file; + FILE* debug_label_dibit_file; + FILE* debug_label_imbe_file; +#endif + } dsd_state; /* @@ -189,7 +212,7 @@ typedef struct #define X2TDMA_MS_DATA_SYNC "313113333111111133333313" #define X2TDMA_MS_VOICE_SYNC "131331111333333311111131" -#define DSTAR_HD "131313131333133113131111" +#define DSTAR_HD "131313131333133113131111" #define INV_DSTAR_HD "313131313111311331313333" #define DSTAR_SYNC "313131313133131113313111" #define INV_DSTAR_SYNC "131313131311313331131333" @@ -223,7 +246,10 @@ void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state); void playSynthesizedVoice (dsd_opts * opts, dsd_state * state); void openAudioOutDevice (dsd_opts * opts, int speed); void openAudioInDevice (dsd_opts * opts); + int getDibit (dsd_opts * opts, dsd_state * state); +int get_dibit_and_analog_signal (dsd_opts * opts, dsd_state * state, int * out_analog_signal); + void skipDibit (dsd_opts * opts, dsd_state * state, int count); void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d); void saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d); @@ -260,6 +286,7 @@ void processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mf void processHDU (dsd_opts * opts, dsd_state * state); void processLDU1 (dsd_opts * opts, dsd_state * state); void processLDU2 (dsd_opts * opts, dsd_state * state); +void processTDU (dsd_opts * opts, dsd_state * state); void processTDULC (dsd_opts * opts, dsd_state * state); void processProVoice (dsd_opts * opts, dsd_state * state); void processX2TDMAdata (dsd_opts * opts, dsd_state * state); diff --git a/dsd_audio.c b/dsd_audio.c index 4d35384..3a1e335 100644 --- a/dsd_audio.c +++ b/dsd_audio.c @@ -90,18 +90,19 @@ processAudio (dsd_opts * opts, dsd_state * state) gaindelta = (float) 0; } - if(opts->audio_gain >= 0){ - // adjust output gain - state->audio_out_temp_buf_p = state->audio_out_temp_buf; - for (n = 0; n < 160; n++) - { - *state->audio_out_temp_buf_p = (state->aout_gain + ((float) n * gaindelta)) * (*state->audio_out_temp_buf_p); - state->audio_out_temp_buf_p++; - } - state->aout_gain += ((float) 160 * gaindelta); - } + if(opts->audio_gain >= 0) + { + // adjust output gain + state->audio_out_temp_buf_p = state->audio_out_temp_buf; + for (n = 0; n < 160; n++) + { + *state->audio_out_temp_buf_p = (state->aout_gain + ((float) n * gaindelta)) * (*state->audio_out_temp_buf_p); + state->audio_out_temp_buf_p++; + } + state->aout_gain += ((float) 160 * gaindelta); + } - // copy audio datat to output buffer and upsample if necessary + // copy audio data to output buffer and upsample if necessary state->audio_out_temp_buf_p = state->audio_out_temp_buf; if (opts->split == 0) { @@ -117,13 +118,13 @@ processAudio (dsd_opts * opts, dsd_state * state) // copy to output (short) buffer for (n = 0; n < 960; n++) { - if (*state->audio_out_float_buf_p > (float) 32760) + if (*state->audio_out_float_buf_p > 32767.0F) { - *state->audio_out_float_buf_p = (float) 32760; + *state->audio_out_float_buf_p = 32767.0F; } - else if (*state->audio_out_float_buf_p < (float) -32760) + else if (*state->audio_out_float_buf_p < -32768.0F) { - *state->audio_out_float_buf_p = (float) -32760; + *state->audio_out_float_buf_p = -32768.0F; } *state->audio_out_buf_p = (short) *state->audio_out_float_buf_p; state->audio_out_buf_p++; @@ -135,13 +136,13 @@ processAudio (dsd_opts * opts, dsd_state * state) { for (n = 0; n < 160; n++) { - if (*state->audio_out_temp_buf_p > (float) 32760) + if (*state->audio_out_temp_buf_p > 32767.0F) { - *state->audio_out_temp_buf_p = (float) 32760; + *state->audio_out_temp_buf_p = 32767.0F; } - else if (*state->audio_out_temp_buf_p < (float) -32760) + else if (*state->audio_out_temp_buf_p < -32768.0F) { - *state->audio_out_temp_buf_p = (float) -32760; + *state->audio_out_temp_buf_p = -32768.0F; } *state->audio_out_buf_p = (short) *state->audio_out_temp_buf_p; state->audio_out_buf_p++; @@ -240,15 +241,18 @@ openAudioOutDevice (dsd_opts * opts, int speed) { // get info of device/file struct stat stat_buf; - if(stat(opts->audio_out_dev, &stat_buf) != 0) { - printf("Error, couldn't open %s\n", opts->audio_out_dev); - exit(1); - } + if(stat(opts->audio_out_dev, &stat_buf) != 0) + { + printf("Error, couldn't open %s\n", opts->audio_out_dev); + exit(1); + } - if( !(S_ISCHR(stat_buf.st_mode) || S_ISBLK(stat_buf.st_mode))) { // this is not a device - printf("Error, %s is not a device. use -w filename for wav output.\n", opts->audio_out_dev); - exit(1); - } + if( !(S_ISCHR(stat_buf.st_mode) || S_ISBLK(stat_buf.st_mode))) + { + // this is not a device + printf("Error, %s is not a device. use -w filename for wav output.\n", opts->audio_out_dev); + exit(1); + } #ifdef SOLARIS sample_info_t aset, aget; @@ -320,22 +324,29 @@ openAudioInDevice (dsd_opts * opts) { // get info of device/file struct stat stat_buf; - if (stat(opts->audio_in_dev, &stat_buf) != 0) { - printf("Error, couldn't open %s\n", opts->audio_in_dev); - exit(1); - } - if(S_ISREG(stat_buf.st_mode)) { // is this a regular file? then process with libsndfile. - opts->audio_in_type = 1; - opts->audio_in_file_info = calloc(1, sizeof(SF_INFO)); - opts->audio_in_file_info->channels = 1; - opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info); - if(opts->audio_in_file == NULL) { - printf ("Error, couldn't open file %s\n", opts->audio_in_dev); - exit(1); + if (stat(opts->audio_in_dev, &stat_buf) != 0) + { + printf("Error, couldn't open %s\n", opts->audio_in_dev); + exit(1); } - } - else { // this is a device, use old handling - opts->audio_in_type = 0; + if (S_ISREG(stat_buf.st_mode)) + { + // is this a regular file? then process with libsndfile. + opts->audio_in_type = 1; + opts->audio_in_file_info = calloc(1, sizeof(SF_INFO)); + opts->audio_in_file_info->channels = 1; + opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info); + + if(opts->audio_in_file == NULL) + { + printf ("Error, couldn't open file %s\n", opts->audio_in_dev); + exit(1); + } + } + else + { + // this is a device, use old handling + opts->audio_in_type = 0; #ifdef SOLARIS sample_info_t aset, aget; int rgain; diff --git a/dsd_dibit.c b/dsd_dibit.c index 62bbd20..ee3ea58 100644 --- a/dsd_dibit.c +++ b/dsd_dibit.c @@ -15,29 +15,120 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include + #include "dsd.h" -int -getDibit (dsd_opts * opts, dsd_state * state) +#include "p25p1_heuristics.h" + +static void +print_datascope(dsd_opts* opts, dsd_state* state, int* sbuf2) { - // returns one dibit value - int i, j, o, symbol; - int sbuf2[128]; - int spectrum[64]; + int i, j, o; char modulation[8]; + int spectrum[64]; + + if (state->rf_mod == 0) + { + sprintf (modulation, "C4FM"); + } + else if (state->rf_mod == 1) + { + sprintf (modulation, "QPSK"); + } + else if (state->rf_mod == 2) + { + sprintf (modulation, "GFSK"); + } + + for (i = 0; i < 64; i++) + { + spectrum[i] = 0; + } + for (i = 0; i < opts->ssize; i++) + { + o = (sbuf2[i] + 32768) / 1024; + spectrum[o]++; + } + if (state->symbolcnt > (4800 / opts->scoperate)) + { + state->symbolcnt = 0; + printf ("\n"); + printf ("Demod mode: %s Nac: %4X\n", modulation, state->nac); + printf ("Frame Type: %s Talkgroup: %7i\n", state->ftype, state->lasttg); + printf ("Frame Subtype: %s Source: %12i\n", state->fsubtype, state->lastsrc); + printf ("TDMA activity: %s %s Voice errors: %s\n", state->slot0light, state->slot1light, state->err_str); + printf ("+----------------------------------------------------------------+\n"); + for (i = 0; i < 10; i++) + { + printf ("|"); + for (j = 0; j < 64; j++) + { + if (i == 0) + { + if ((j == ((state->min) + 32768) / 1024) || (j == ((state->max) + 32768) / 1024)) + { + printf ("#"); + } + else if ((j == ((state->lmid) + 32768) / 1024) || (j == ((state->umid) + 32768) / 1024)) + { + printf ("^"); + } + else if (j == (state->center + 32768) / 1024) + { + printf ("!"); + } + else + { + if (j == 32) + { + printf ("|"); + } + else + { + printf (" "); + } + } + } + else + { + if (spectrum[j] > 9 - i) + { + printf ("*"); + } + else + { + if (j == 32) + { + printf ("|"); + } + else + { + printf (" "); + } + } + } + } + printf ("|\n"); + } + printf ("+----------------------------------------------------------------+\n"); + } +} + +static void +use_symbol (dsd_opts* opts, dsd_state* state, int symbol) +{ + int i; + int sbuf2[128]; int lmin, lmax, lsum; - state->numflips = 0; - - symbol = getSymbol (opts, state, 1); - state->sbuf[state->sidx] = symbol; - for (i = 0; i < opts->ssize; i++) { sbuf2[i] = state->sbuf[i]; } qsort (sbuf2, opts->ssize, sizeof (int), comp); + // continuous update of min/max in rf_mod=1 (QPSK) mode // in c4fm min/max must only be updated during sync if (state->rf_mod == 1) @@ -69,8 +160,8 @@ getDibit (dsd_opts * opts, dsd_state * state) state->center = ((state->max) + (state->min)) / 2; state->umid = (((state->max) - state->center) * 5 / 8) + state->center; state->lmid = (((state->min) - state->center) * 5 / 8) + state->center; - state->maxref = ((state->max) * 0.80); - state->minref = ((state->min) * 0.80); + state->maxref = (int)((state->max) * 0.80F); + state->minref = (int)((state->min) * 0.80F); } else { @@ -78,98 +169,14 @@ getDibit (dsd_opts * opts, dsd_state * state) state->minref = state->min; } + // Increase sidx if (state->sidx == (opts->ssize - 1)) { - state->sidx = 0; if (opts->datascope == 1) { - if (state->rf_mod == 0) - { - sprintf (modulation, "C4FM"); - } - else if (state->rf_mod == 1) - { - sprintf (modulation, "QPSK"); - } - else if (state->rf_mod == 2) - { - sprintf (modulation, "GFSK"); - } - - for (i = 0; i < 64; i++) - { - spectrum[i] = 0; - } - for (i = 0; i < opts->ssize; i++) - { - o = (sbuf2[i] + 32768) / 1024; - spectrum[o]++; - } - if (state->symbolcnt > (4800 / opts->scoperate)) - { - state->symbolcnt = 0; - printf ("\n"); - printf ("Demod mode: %s Nac: %4X\n", modulation, state->nac); - printf ("Frame Type: %s Talkgroup: %7i\n", state->ftype, state->lasttg); - printf ("Frame Subtype: %s Source: %12i\n", state->fsubtype, state->lastsrc); - printf ("TDMA activity: %s %s Voice errors: %s\n", state->slot0light, state->slot1light, state->err_str); - printf ("+----------------------------------------------------------------+\n"); - for (i = 0; i < 10; i++) - { - printf ("|"); - for (j = 0; j < 64; j++) - { - if (i == 0) - { - if ((j == ((state->min) + 32768) / 1024) || (j == ((state->max) + 32768) / 1024)) - { - printf ("#"); - } - else if ((j == ((state->lmid) + 32768) / 1024) || (j == ((state->umid) + 32768) / 1024)) - { - printf ("^"); - } - else if (j == (state->center + 32768) / 1024) - { - printf ("!"); - } - else - { - if (j == 32) - { - printf ("|"); - } - else - { - printf (" "); - } - } - } - else - { - if (spectrum[j] > 9 - i) - { - printf ("*"); - } - else - { - if (j == 32) - { - printf ("|"); - } - else - { - printf (" "); - } - } - } - } - printf ("|\n"); - } - printf ("+----------------------------------------------------------------+\n"); - } + print_datascope(opts, state, sbuf2); } } else @@ -179,12 +186,39 @@ getDibit (dsd_opts * opts, dsd_state * state) if (state->dibit_buf_p > state->dibit_buf + 900000) { - state->dibit_buf_p = state->dibit_buf + 200; + state->dibit_buf_p = state->dibit_buf + 200; + } +} + +static int +invert_dibit(int dibit) +{ + switch (dibit) + { + case 0: + return 2; + case 1: + return 3; + case 2: + return 0; + case 3: + return 1; } + // Error, shouldn't be here + assert(0); + return -1; +} + +static int digitize (dsd_opts* opts, dsd_state* state, int symbol) +{ // determine dibit state if ((state->synctype == 6) || (state->synctype == 14)|| (state->synctype == 18)) { + // 6 +D-STAR + // 14 +ProVoice + // 18 +D-STAR_HD + if (symbol > state->center) { *state->dibit_buf_p = 1; @@ -217,7 +251,8 @@ getDibit (dsd_opts * opts, dsd_state * state) return (0); // +1 } } - else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) || (state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13)) + else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) || + (state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13) || (state->synctype == 17)) { // 1 -P25p1 // 3 -X2-TDMA (inverted signal voice frame) @@ -225,37 +260,53 @@ getDibit (dsd_opts * opts, dsd_state * state) // 9 -NXDN (inverted voice frame) // 11 -DMR (inverted signal voice frame) // 13 -DMR (inverted signal data frame) + // 17 -NXDN (inverted data frame) - if (symbol > state->center) + int valid; + int dibit; + + valid = 0; + + if (state->synctype == 1) { - if (symbol > state->umid) + // Use the P25 heuristics if available + valid = estimate_symbol(state->rf_mod, &(state->inv_p25_heuristics), state->last_dibit, symbol, &dibit); + } + + if (valid == 0) + { + // Revert to the original approach: choose the symbol according to the regions delimited + // by center, umid and lmid + if (symbol > state->center) { - *state->dibit_buf_p = 1; // store non-inverted values in dibit_buf - state->dibit_buf_p++; - return (3); + if (symbol > state->umid) + { + dibit = 3; // -3 + } + else + { + dibit = 2; // -1 + } } else { - *state->dibit_buf_p = 0; - state->dibit_buf_p++; - return (2); - } - } - else - { - if (symbol < state->lmid) - { - *state->dibit_buf_p = 3; - state->dibit_buf_p++; - return (1); - } - else - { - *state->dibit_buf_p = 2; - state->dibit_buf_p++; - return (0); + if (symbol < state->lmid) + { + dibit = 1; // +3 + } + else + { + dibit = 0; // +2 + } } } + + state->last_dibit = dibit; + + // store non-inverted values in dibit_buf + *state->dibit_buf_p = invert_dibit(dibit); + state->dibit_buf_p++; + return dibit; } else { @@ -266,41 +317,112 @@ getDibit (dsd_opts * opts, dsd_state * state) // 10 +DMR (non inverted signal data frame) // 12 +DMR (non inverted signal voice frame) // 16 +NXDN (non inverted data frame) - // 17 -NXDN (inverted data frame) ??? - if (symbol > state->center) + int valid; + int dibit; + + valid = 0; + + if (state->synctype == 0) { - if (symbol > state->umid) + // Use the P25 heuristics if available + valid = estimate_symbol(state->rf_mod, &(state->p25_heuristics), state->last_dibit, symbol, &dibit); + } + + if (valid == 0) + { + // Revert to the original approach: choose the symbol according to the regions delimited + // by center, umid and lmid + if (symbol > state->center) { - *state->dibit_buf_p = 1; - state->dibit_buf_p++; - return (1); + if (symbol > state->umid) + { + dibit = 1; // +3 + } + else + { + dibit = 0; // +1 + } } else { - *state->dibit_buf_p = 0; - state->dibit_buf_p++; - return (0); - } - } - else - { - if (symbol < state->lmid) - { - *state->dibit_buf_p = 3; - state->dibit_buf_p++; - return (3); - } - else - { - *state->dibit_buf_p = 2; - state->dibit_buf_p++; - return (2); + if (symbol < state->lmid) + { + dibit = 3; // -3 + } + else + { + dibit = 2; // -1 + } } } + + state->last_dibit = dibit; + + *state->dibit_buf_p = dibit; + state->dibit_buf_p++; + return dibit; } } +int +get_dibit_and_analog_signal (dsd_opts* opts, dsd_state* state, int* out_analog_signal) +{ + int symbol; + int dibit; + +#ifdef TRACE_DSD + unsigned int l, r; +#endif + + state->numflips = 0; + +#ifdef TRACE_DSD + l = state->debug_sample_index; +#endif + + symbol = getSymbol (opts, state, 1); + +#ifdef TRACE_DSD + r = state->debug_sample_index; +#endif + + // + state->sbuf[state->sidx] = symbol; + if (out_analog_signal != NULL) + { + *out_analog_signal = symbol; + } + + use_symbol (opts, state, symbol); + + dibit = digitize (opts, state, symbol); + +#ifdef TRACE_DSD + { + float left, right; + if (state->debug_label_dibit_file == NULL) { + state->debug_label_dibit_file = fopen ("pp_label_dibit.txt", "w"); + } + left = l / 48000.0; + right = r / 48000.0; + fprintf(state->debug_label_dibit_file, "%f\t%f\t%i\n", left, right, dibit); + } +#endif + + return dibit; +} + +/** + * \brief This important method reads the last analog signal value (getSymbol call) and digitizes it. + * Depending of the ongoing transmission it in converted into a bit (0/1) or a di-bit (00/01/10/11). + */ +int +getDibit (dsd_opts* opts, dsd_state* state) +{ + return get_dibit_and_analog_signal (opts, state, NULL); +} + void skipDibit (dsd_opts * opts, dsd_state * state, int count) { diff --git a/dsd_frame.c b/dsd_frame.c index 7b59728..539c391 100644 --- a/dsd_frame.c +++ b/dsd_frame.c @@ -447,10 +447,7 @@ processFrame (dsd_opts * opts, dsd_state * state) state->err_str[0] = 0; sprintf (state->fsubtype, " TDU "); - // Now processing NID - - skipDibit (opts, state, 14); // 28 null bits - status_1 = getDibit (opts, state) + '0'; + processTDU (opts, state); } else if (strcmp (duid, "13") == 0) { diff --git a/dsd_main.c b/dsd_main.c index d59704c..74dca94 100644 --- a/dsd_main.c +++ b/dsd_main.c @@ -25,6 +25,7 @@ #include "dmr_const.h" #include "provoice_const.h" #include "git_ver.h" +#include "p25p1_heuristics.h" int comp (const void *a, const void *b) @@ -224,6 +225,15 @@ initState (dsd_state * state) state->debug_audio_errors = 0; state->debug_header_errors = 0; state->debug_header_critical_errors = 0; + +#ifdef TRACE_DSD + state->debug_sample_index = 0; + state->debug_label_file = NULL; + state->debug_label_dibit_file = NULL; + state->debug_label_imbe_file = NULL; +#endif + + initialize_p25_heuristics(&state->p25_heuristics); } void @@ -305,7 +315,17 @@ liveScanner (dsd_opts * opts, dsd_state * state) while (state->synctype != -1) { processFrame (opts, state); + +#ifdef TRACE_DSD + state->debug_prefix = 'S'; +#endif + state->synctype = getFrameSync (opts, state); + +#ifdef TRACE_DSD + state->debug_prefix = '\0'; +#endif + // recalibrate center/umid/lmid state->center = ((state->max) + (state->min)) / 2; state->umid = (((state->max) - state->center) * 5 / 8) + state->center; @@ -328,6 +348,28 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state) printf("Total header errors: %i\n", state->debug_header_errors); printf("Total irrecoverable header errors: %i\n", state->debug_header_critical_errors); + //debug_print_heuristics(&(state->p25_heuristics)); + + printf("\n"); + printf("+P25 BER estimate: %.2f%%\n", get_P25_BER_estimate(&state->p25_heuristics)); + printf("-P25 BER estimate: %.2f%%\n", get_P25_BER_estimate(&state->inv_p25_heuristics)); + printf("\n"); + +#ifdef TRACE_DSD + if (state->debug_label_file != NULL) { + fclose(state->debug_label_file); + state->debug_label_file = NULL; + } + if(state->debug_label_dibit_file != NULL) { + fclose(state->debug_label_dibit_file); + state->debug_label_dibit_file = NULL; + } + if(state->debug_label_imbe_file != NULL) { + fclose(state->debug_label_imbe_file); + state->debug_label_imbe_file = NULL; + } +#endif + printf ("Exiting.\n"); exit (0); } @@ -342,7 +384,6 @@ sigfun (int sig) int main (int argc, char **argv) { - int c; extern char *optarg; extern int optind, opterr, optopt; diff --git a/dsd_symbol.c b/dsd_symbol.c index 8915b55..be830bb 100644 --- a/dsd_symbol.c +++ b/dsd_symbol.c @@ -20,7 +20,6 @@ int getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) { - short sample; int i, sum, symbol, count; ssize_t result; @@ -78,6 +77,8 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) } state->jitter = -1; } + + // Read the new sample from the input if(opts->audio_in_type == 0) { result = read (opts->audio_in_fd, &sample, 2); } @@ -87,15 +88,20 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) cleanupAndExit (opts, state); } } - // printf("res: %zd\n, offset: %lld", result, sf_seek(opts->audio_in_file, 0, SEEK_CUR)); + +#ifdef TRACE_DSD + state->debug_sample_index++; +#endif + + // printf("res: %zd\n, offset: %lld", result, sf_seek(opts->audio_in_file, 0, SEEK_CUR)); if (opts->use_cosine_filter) - { - if (state->lastsynctype >= 10 && state->lastsynctype <= 13) - sample = dmr_filter(sample); - else if (state->lastsynctype == 8 || state->lastsynctype == 9 || + { + if (state->lastsynctype >= 10 && state->lastsynctype <= 13) + sample = dmr_filter(sample); + else if (state->lastsynctype == 8 || state->lastsynctype == 9 || state->lastsynctype == 16 || state->lastsynctype == 17) - sample = nxdn_filter(sample); - } + sample = nxdn_filter(sample); + } if ((sample > state->max) && (have_sync == 1) && (state->rf_mod == 0)) { @@ -190,14 +196,57 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) } else { - if (((i >= state->symbolCenter - 1) && (i <= state->symbolCenter + 2) && (state->rf_mod == 0)) || (((i == state->symbolCenter) || (i == state->symbolCenter + 1)) && (state->rf_mod != 0))) + if (state->rf_mod == 0) { - sum += sample; - count++; + // 0: C4FM modulation + + if ((i >= state->symbolCenter - 1) && (i <= state->symbolCenter + 2)) + { + sum += sample; + count++; + } + +#ifdef TRACE_DSD + if (i == state->symbolCenter - 1) { + state->debug_sample_left_edge = state->debug_sample_index - 1; + } + if (i == state->symbolCenter + 2) { + state->debug_sample_right_edge = state->debug_sample_index - 1; + } +#endif + } + else + { + // 1: QPSK modulation + // 2: GFSK modulation + // Note: this has been changed to use an additional symbol to the left + // On the p25_raw_unencrypted.flac it is evident that the timing + // comes one sample too late. + // This change makes a significant improvement in the BER, at least for + // this file. + //if ((i == state->symbolCenter) || (i == state->symbolCenter + 1)) + if ((i == state->symbolCenter - 1) || (i == state->symbolCenter + 1)) + { + sum += sample; + count++; + } + +#ifdef TRACE_DSD + //if (i == state->symbolCenter) { + if (i == state->symbolCenter - 1) { + state->debug_sample_left_edge = state->debug_sample_index - 1; + } + if (i == state->symbolCenter + 1) { + state->debug_sample_right_edge = state->debug_sample_index - 1; + } +#endif } } + + state->lastsample = sample; - } + } // for + symbol = (sum / count); if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1)) @@ -212,6 +261,27 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) } } +#ifdef TRACE_DSD + if (state->samplesPerSymbol == 10) { + float left, right; + if (state->debug_label_file == NULL) { + state->debug_label_file = fopen ("pp_label.txt", "w"); + } + left = state->debug_sample_left_edge / 48000.0; + right = state->debug_sample_right_edge / 48000.0; + if (state->debug_prefix != '\0') { + if (state->debug_prefix == 'I') { + fprintf(state->debug_label_file, "%f\t%f\t%c%c %i\n", left, right, state->debug_prefix, state->debug_prefix_2, symbol); + } else { + fprintf(state->debug_label_file, "%f\t%f\t%c %i\n", left, right, state->debug_prefix, symbol); + } + } else { + fprintf(state->debug_label_file, "%f\t%f\t%i\n", left, right, symbol); + } + } +#endif + + state->symbolcnt++; return (symbol); } diff --git a/fcs.h b/fcs.h index 314ebac..09eae08 100644 --- a/fcs.h +++ b/fcs.h @@ -65,12 +65,10 @@ uint16_t calc_fcs (unsigned char * dvstartframe, int size) { // radio header (fields flag1, flag2, flag3, destination, departure, companion, // own1 and own2) uint16_t m_crc; - -m_crc=0xFFFF; - int loop; unsigned short tmp; +m_crc=0xFFFF; for (loop=0; loop < size; loop++) { tmp = (m_crc & 0x00ff) ^ dvstartframe[loop]; diff --git a/p25p1_check_hdu.cpp b/p25p1_check_hdu.cpp index 0a58cf5..cf81289 100644 --- a/p25p1_check_hdu.cpp +++ b/p25p1_check_hdu.cpp @@ -3,13 +3,19 @@ #include "ReedSolomon.hpp" #include "Golay24.hpp" -//#define __CHECK_HDU_DEBUG__ +// Uncomment for very verbose trace messages +//#define CHECK_HDU_DEBUG -int check_and_fix_golay24(char* hex, char* parity, int* fixed_errors) +// The following methods are just a C bridge for the C++ implementations of the Golay and ReedSolomon +// algorithms. + +static DSDGolay24 golay24; + +static DSDReedSolomon_36_20_17 reed_solomon_36_20_17; + +int check_and_fix_golay_24_6(char* hex, char* parity, int* fixed_errors) { - static DSDGolay24 golay24; - -#ifdef __CHECK_HDU_DEBUG__ +#ifdef CHECK_HDU_DEBUG printf("["); for(unsigned int i=0; i<6; i++) { printf("%c", (hex[i] != 0)? 'X': ' '); @@ -21,9 +27,9 @@ int check_and_fix_golay24(char* hex, char* parity, int* fixed_errors) printf("]"); #endif - int irrecoverable_errors = golay24.decode(hex, parity, fixed_errors); + int irrecoverable_errors = golay24.decode_6(hex, parity, fixed_errors); -#ifdef __CHECK_HDU_DEBUG__ +#ifdef CHECK_HDU_DEBUG printf(" -> ["); for(unsigned int i=0; i<6; i++) { printf("%c", (hex[i] != 0)? 'X': ' '); @@ -40,11 +46,53 @@ int check_and_fix_golay24(char* hex, char* parity, int* fixed_errors) return irrecoverable_errors; } +int check_and_fix_golay_24_12(char* dodeca, char* parity, int* fixed_errors) +{ +#ifdef CHECK_HDU_DEBUG + printf("["); + for(unsigned int i=0; i<12; i++) { + printf("%c", (dodeca[i] != 0)? 'X': ' '); + } + printf("] ["); + for(unsigned int i=12; i<24; i++) { + printf("%c", (parity[i-12] != 0)? 'X': ' '); + } + printf("]"); +#endif + + int irrecoverable_errors = golay24.decode_12(dodeca, parity, fixed_errors); + +#ifdef CHECK_HDU_DEBUG + printf(" -> ["); + for(unsigned int i=0; i<12; i++) { + printf("%c", (dodeca[i] != 0)? 'X': ' '); + } + printf("]"); + if (irrecoverable_errors) { + printf(" Errors: >4"); + } else { + printf(" Errors: %i", *fixed_errors); + } + printf("\n"); +#endif + + return irrecoverable_errors; +} + +void encode_golay_24_6(char* hex, char* out_parity) +{ + golay24.encode_6(hex, out_parity); +} + +void encode_golay_24_12(char* dodeca, char* out_parity) +{ + golay24.encode_12(dodeca, out_parity); +} + + int check_and_fix_redsolomon_36_20_17(char* data, char* parity) { - static DSDReedSolomon_36_20_17 reed_solomon_36_20_17; - -#ifdef __CHECK_HDU_DEBUG__ +#ifdef CHECK_HDU_DEBUG char original[20][6]; for (int i = 0; i < 20; i++) { for (int j = 0; j < 6; j++) { @@ -55,7 +103,7 @@ int check_and_fix_redsolomon_36_20_17(char* data, char* parity) int irrecoverable_errors = reed_solomon_36_20_17.decode(data, parity); -#ifdef __CHECK_HDU_DEBUG__ +#ifdef CHECK_HDU_DEBUG printf("Results for Reed-Solomon code (36,20,17)\n\n"); if (irrecoverable_errors == 0) { printf(" i original fixed\n"); @@ -86,3 +134,9 @@ int check_and_fix_redsolomon_36_20_17(char* data, char* parity) return irrecoverable_errors; } + +void encode_reedsolomon_36_20_17(char* hex_data, char* fixed_parity) +{ + reed_solomon_36_20_17.encode(hex_data, fixed_parity); +} + diff --git a/p25p1_check_hdu.h b/p25p1_check_hdu.h index ef74a6e..ff60d88 100644 --- a/p25p1_check_hdu.h +++ b/p25p1_check_hdu.h @@ -1,18 +1,42 @@ -#ifndef __P25P1_CHECK_HDU_H__ -#define __P25P1_CHECK_HDU_H__ + +#ifndef P25P1_CHECK_HDU_H_f5f079faf2d64cf5831e1da1ab83b9ba +#define P25P1_CHECK_HDU_H_f5f079faf2d64cf5831e1da1ab83b9ba #ifdef __cplusplus extern "C" { #endif /** - * Attempts to correct an hex (6 bit) word using the Golay(24,12,8) FEC. - * \param hex The 6 bit word to error correct, given as a char array of 6 elements, each one bit. - * \param parity A 12 bit word with the Golay parity data, given as a char array of 12 elements. + * Attempts to correct an hex (6-bit) word using the Golay(24,12,8) FEC. + * \param hex The 6-bit word to error correct, given as a char array of 6 elements, one bit each. + * \param parity A 12-bit word with the Golay parity data, given as a char array of 12 elements. * \param fixed_error Output. Filled with the number of errors fixed in the input. * \return 1 if there were uncorrectable errors in the input, 0 otherwise. */ -int check_and_fix_golay24(char* hex, char* parity, int* fixed_errors); +int check_and_fix_golay_24_6(char* hex, char* parity, int* fixed_errors); + +/** + * Attempts to correct a 12-bit word using the Golay(24,12,8) FEC. + * \param dodeca The 12-bit word to error correct, given as a char array of 12 elements, one bit each. + * \param parity A 12-bit word with the Golay parity data, given as a char array of 12 elements. + * \param fixed_error Output. Filled with the number of errors fixed in the input. + * \return 1 if there were uncorrectable errors in the input, 0 otherwise. + */ +int check_and_fix_golay_24_12(char* dodeca, char* parity, int* fixed_errors); + +/** + * Encodes an hex word using the Golay(24,12,8) FEC. + * \param hex A 6-bit word to encode. + * \param out_parity The address to be filled with the calculated Golay parity. + */ +void encode_golay_24_6(char* hex, char* out_parity); + +/** + * Encodes an 12-bitword using the Golay(24,12,8) FEC. + * \param dodeca A 12-bit word to encode. + * \param out_parity The address to be filled with the calculated Golay parity. + */ +void encode_golay_24_12(char* dodeca, char* out_parity); /** * Attempts to correct 20 hex words using the Reed-Solomon(36,20,17) FEC. @@ -22,8 +46,15 @@ int check_and_fix_golay24(char* hex, char* parity, int* fixed_errors); */ int check_and_fix_redsolomon_36_20_17(char* data, char* parity); +/** + * Calculates the Reed-Solomon parity of 20 words of 6 bits each. + * \param hex_data The address with the words whose parity we want to calculate. + * \param fixed_parity The address to be filled with the calculated parity. 16 words of 6 bits are produced. + */ +void encode_reedsolomon_36_20_17(char* hex_data, char* fixed_parity); + #ifdef __cplusplus } #endif -#endif // __P25P1_CHECK_HDU_H__ +#endif // P25P1_CHECK_HDU_H_f5f079faf2d64cf5831e1da1ab83b9ba diff --git a/p25p1_check_ldu.cpp b/p25p1_check_ldu.cpp index 82ec0ee..15efdd3 100644 --- a/p25p1_check_ldu.cpp +++ b/p25p1_check_ldu.cpp @@ -4,22 +4,29 @@ #include "Hamming.hpp" #include "ReedSolomon.hpp" +// Uncomment for very verbose trace messages +//#define CHECK_LDU_DEBUG -//#define __CHECK_HDU_DEBUG__ +// The following methods are just a C bridge for the C++ implementations of the Golay and ReedSolomon +// algorithms. +static Hamming_10_6_3_TableImpl hamming; +static DSDReedSolomon_24_12_13 reed_solomon_24_12_13; +static DSDReedSolomon_24_16_9 reed_solomon_24_16_9; -int check_and_fix_hamming_10_12_13(char* hex, char* parity) +int check_and_fix_hamming_10_6_3(char* hex, char* parity) { - static Hamming_10_6_3_TableImpl hamming; - return hamming.decode(hex, parity); } -int check_and_fix_redsolomon_24_12_13(char* data, char* parity) +void encode_hamming_10_6_3(char* hex, char* out_parity) { - static DSDReedSolomon_24_12_13 reed_solomon_24_12_13; + hamming.encode(hex, out_parity); +} -#ifdef __CHECK_HDU_DEBUG__ +int check_and_fix_reedsolomon_24_12_13(char* data, char* parity) +{ +#ifdef CHECK_LDU_DEBUG char original[12][6]; for (int i = 0; i < 12; i++) { for (int j = 0; j < 6; j++) { @@ -30,7 +37,7 @@ int check_and_fix_redsolomon_24_12_13(char* data, char* parity) int irrecoverable_error = reed_solomon_24_12_13.decode(data, parity); -#ifdef __CHECK_HDU_DEBUG__ +#ifdef CHECK_LDU_DEBUG printf("Results for Reed-Solomon code (24,12,13)\n\n"); if (irrecoverable_error == 0) { printf(" i original fixed\n"); @@ -62,11 +69,14 @@ int check_and_fix_redsolomon_24_12_13(char* data, char* parity) return irrecoverable_error; } -int check_and_fix_redsolomon_24_16_9(char* data, char* parity) +void encode_reedsolomon_24_12_13(char* hex_data, char* fixed_parity) { - static DSDReedSolomon_24_16_9 reed_solomon_24_16_9; + reed_solomon_24_12_13.encode(hex_data, fixed_parity); +} -#ifdef __CHECK_HDU_DEBUG__ +int check_and_fix_reedsolomon_24_16_9(char* data, char* parity) +{ +#ifdef CHECK_LDU_DEBUG char original[16][6]; for (int i = 0; i < 16; i++) { for (int j = 0; j < 6; j++) { @@ -77,7 +87,7 @@ int check_and_fix_redsolomon_24_16_9(char* data, char* parity) int irrecoverable_error = reed_solomon_24_16_9.decode(data, parity); -#ifdef __CHECK_HDU_DEBUG__ +#ifdef CHECK_LDU_DEBUG printf("Results for Reed-Solomon code (24,16,9)\n\n"); if (irrecoverable_error == 0) { printf(" i original fixed\n"); @@ -108,3 +118,8 @@ int check_and_fix_redsolomon_24_16_9(char* data, char* parity) return irrecoverable_error; } + +void encode_reedsolomon_24_16_9(char* hex_data, char* fixed_parity) +{ + reed_solomon_24_16_9.encode(hex_data, fixed_parity); +} diff --git a/p25p1_check_ldu.h b/p25p1_check_ldu.h index 7cc22bf..aac1220 100644 --- a/p25p1_check_ldu.h +++ b/p25p1_check_ldu.h @@ -1,11 +1,25 @@ -#ifndef __P25P1_CHECK_LDU_H__ -#define __P25P1_CHECK_LDU_H__ + +#ifndef P25P1_CHECK_LDU_H_c1734445a67e47caa25673d7a4ce7520 +#define P25P1_CHECK_LDU_H_c1734445a67e47caa25673d7a4ce7520 #ifdef __cplusplus extern "C" { #endif -int check_and_fix_hamming_10_12_13(char* hex, char* parity); +/** + * Attempts to error correct a hex (6-bit) word using the Hamming(10,6,3) FEC. + * \param hex The 6-bit word to error correct. + * \param parity The parity to use in the error correction. 4 bits. + * \return The estimated error count. It might be erroneous. + */ +int check_and_fix_hamming_10_6_3(char* hex, char* parity); + +/** + * Encodes an hex word with the Hamming(10,6,3) FEC. + * \param hex The 6-bit word to error correct. + * \param out_parity The address where to store the calculated parity. 4 bytes are used, one for each bit. + */ +void encode_hamming_10_6_3(char* hex, char* out_parity); /** * Attempts to correct 12 hex words using the Reed-Solomon(24,12,13) FEC. @@ -13,18 +27,32 @@ int check_and_fix_hamming_10_12_13(char* hex, char* parity); * \param parity The corresponding 12 hex words with the parity information. * \return 1 if irrecoverable errors have been detected, 0 otherwise. */ -int check_and_fix_redsolomon_24_12_13(char* data, char* parity); +int check_and_fix_reedsolomon_24_12_13(char* data, char* parity); + +/** + * Encodes 12 hex words with the Reed-Solomon(24,12,13) FEC. + * \param hex_data The packed 12 hex words to encode. + * \fixed_parity The address were to store the 12 hex words with the Reed-Solomon parity. + */ +void encode_reedsolomon_24_12_13(char* hex_data, char* fixed_parity); /** * Attempts to correct 16 hex words using the Reed-Solomon(24,16,9) FEC. - * \param data The packed hex words, each of 6 chars, one after the other. + * \param data The packed 16 hex words, each of 6 chars, one after the other. * \param parity The corresponding 8 hex words with the parity information. * \return 1 if irrecoverable errors have been detected, 0 otherwise. */ -int check_and_fix_redsolomon_24_16_9(char* data, char* parity); +int check_and_fix_reedsolomon_24_16_9(char* data, char* parity); + +/** + * Encodes 12 hex words with the Reed-Solomon(24,16,9) FEC. + * \param hex_data The packed 16 hex words to encode. + * \fixed_parity The address were to store the 8 hex words with the Reed-Solomon parity. + */ +void encode_reedsolomon_24_16_9(char* hex_data, char* fixed_parity); #ifdef __cplusplus } #endif -#endif // __P25P1_CHECK_LDU_H__ +#endif // P25P1_CHECK_LDU_H_c1734445a67e47caa25673d7a4ce7520 diff --git a/p25p1_check_nid.cpp b/p25p1_check_nid.cpp index 9a4e305..668471d 100644 --- a/p25p1_check_nid.cpp +++ b/p25p1_check_nid.cpp @@ -13,7 +13,8 @@ using namespace itpp; itpp::BCH bch(63, 16, 11, "6 3 3 1 1 4 1 3 6 7 2 3 5 4 5 3", true); -/** Convenience class to calculate the parity of the DUID values. Keeps a table with the expected outcomes +/** + * Convenience class to calculate the parity of the DUID values. Keeps a table with the expected outcomes * for fast lookup. */ class ParityTable diff --git a/p25p1_check_nid.h b/p25p1_check_nid.h index 99b8f66..28e83e0 100644 --- a/p25p1_check_nid.h +++ b/p25p1_check_nid.h @@ -1,13 +1,15 @@ -#ifndef __P25P1_CHECK_NID_H__ -#define __P25P1_CHECK_NID_H__ + +#ifndef P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a +#define P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a #ifdef __cplusplus extern "C" { #endif -/** Checks a NID value, returns the fixed NAC, DUID and also an indication if it failed to decode the NID. - * - * \param bch_code Input. An array to the 63 bytes, each containing one bit of the NID. +/** + * Checks a NID value, returns the fixed NAC, DUID and also an indication if it failed to decode the NID. + * \param bch_code Input. An array to the 63 bytes, each containing one bit of the NID. This includes the + * NAC (12 bits), DUID (4 bits) and 47 bits of BCH parity. * \param new_nac Output. An address where to store the calculated NAC value after error correction. Should * be large enough to accommodate for an integer. * \param new_duid Output. An address where to store the calculated DUID value after error correction. Should @@ -21,4 +23,4 @@ int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity } #endif -#endif // __P25P1_CHECK_NID_H__ +#endif // P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a diff --git a/p25p1_hdu.c b/p25p1_hdu.c index a9039c0..bf0135e 100644 --- a/p25p1_hdu.c +++ b/p25p1_hdu.c @@ -17,72 +17,108 @@ #include "dsd.h" - +#include "p25p1_hdu.h" #include "p25p1_check_hdu.h" +#include "p25p1_heuristics.h" -/** - * Read two bits from the stream of data. Takes into account the periodic occurrence of status bits. - * Those are discarded. - */ -void -read_dibit (dsd_opts* opts, dsd_state* state, char* output, int* status_count) +int +read_dibit (dsd_opts* opts, dsd_state* state, char* output, int* status_count, int* analog_signal, int* did_read_status) { int dibit; int status; if (*status_count == 35) { + +#ifdef TRACE_DSD + char prev_prefix = state->debug_prefix; + state->debug_prefix = 's'; +#endif + // Status bits now status = getDibit (opts, state); // TODO: do something useful with the status bits... + if (did_read_status != NULL) { + *did_read_status = 1; + } *status_count = 1; + +#ifdef TRACE_DSD + state->debug_prefix = prev_prefix; +#endif + } else { + if (did_read_status != NULL) { + *did_read_status = 0; + } (*status_count)++; } - dibit = getDibit (opts, state); + dibit = get_dibit_and_analog_signal (opts, state, analog_signal); output[0] = (1 & (dibit >> 1)); // bit 1 output[1] = (1 & dibit); // bit 0 + + return dibit; } -/** - * Read an hex word from the stream of data. - */ void -read_hex (dsd_opts* opts, dsd_state* state, char* hex, int* status_count) +read_dibit_update_analog_data (dsd_opts* opts, dsd_state* state, char* output, unsigned int count, int* status_count, + AnalogSignal* analog_signal_array, int* analog_signal_index) { unsigned int i; + unsigned int debug_left, debug_right; - // Read 3 times a dibit = read 6 bits. - for (i=0; i<=4; i+=2) + for (i=0; idebug_header_errors += fixed_errors; if (irrecoverable_errors != 0) @@ -92,30 +128,98 @@ correct_hex_word (dsd_state* state, char* hex, char* parity) } /** - * Read an hex word, its parity bits and attempts to error correct it using the Golay24 algorithm. + * Reads an hex word, its parity bits and attempts to error correct it using the Golay24 algorithm. */ static void -read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count) +read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count, + AnalogSignal* analog_signal_array, int* analog_signal_index) { char parity[12]; // Read the hex word - read_hex (opts, state, hex, status_count); + read_word (opts, state, hex, 6, status_count, analog_signal_array, analog_signal_index); // Read the parity - read_golay24_parity (opts, state, parity, status_count); + read_golay24_parity (opts, state, parity, status_count, analog_signal_array, analog_signal_index); // Use the Golay24 FEC to correct it. This call modifies the content of hex to fix it, hopefully correct_hex_word (state, hex, parity); } +/** + * Uses the information from a corrected sequence of hex words to update the AnalogSignal data. + * The proper Golay 24 parity is calculated from the corrected hex word so we can also fix the Golay parity + * that we read originally from the signal. + * \param corrected_hex_data Pointer to a sequence of hex words that has been error corrected and therefore + * we trust it's correct. Typically this are hex words that has been decoded successfully using a + * Reed-Solomon variant. + * \param hex_count The number of hex words in the sequence. + * \param analog_signal_array A pointer to the AnalogSignal information for the sequence of hex words. + */ +static void +correct_golay_dibits_6(char* corrected_hex_data, int hex_count, AnalogSignal* analog_signal_array) +{ + int i, j; + int analog_signal_index; + int dibit; + char parity[12]; + + + analog_signal_index = 0; + + for (i=hex_count-1; i>=0; i--) + { + for (j=0; j<6; j+=2) // 3 iterations -> 3 dibits + { + // Given the bits, calculates the dibit + dibit = (corrected_hex_data[i*6+j] << 1) | corrected_hex_data[i*6+j+1]; + // Now we know the dibit we should have read from the signal + analog_signal_array[analog_signal_index].corrected_dibit = dibit; + +#ifdef HEURISTICS_DEBUG + if (analog_signal_array[analog_signal_index].dibit != dibit) + { + printf("HDU data word corrected from %i to %i, analog value %i\n", + analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value); + } +#endif + + analog_signal_index++; + } + + // Calculate the Golay 24 parity for the corrected hex word + encode_golay_24_6(corrected_hex_data+i*6, parity); + + // Now we know the parity we should have read from the signal. Use this information + for (j=0; j<12; j+=2) // 6 iterations -> 6 dibits + { + // Given the bits, calculates the dibit + dibit = (parity[j] << 1) | parity[j+1]; + // Now we know the dibit we should have read from the signal + analog_signal_array[analog_signal_index].corrected_dibit = dibit; + +#ifdef HEURISTICS_DEBUG + if (analog_signal_array[analog_signal_index].dibit != dibit) + { + printf("HDU parity corrected from %i to %i, analog value %i\n", + analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value); + } +#endif + + analog_signal_index++; + } + } +} + +/** + * The important method that processes a full P25 HD unit. + */ void -processHDU (dsd_opts * opts, dsd_state * state) +processHDU(dsd_opts* opts, dsd_state* state) { char mi[73], mfid[9], algid[9], kid[17], tgid[17], tmpstr[255]; - int dibit, i, j; + int i, j; long talkgroup; int algidhex, kidhex; char hex[6]; - int status_count; int status; @@ -124,12 +228,20 @@ processHDU (dsd_opts * opts, dsd_state * state) int irrecoverable_errors; - status_count = 35 - 14; + AnalogSignal analog_signal_array[20*(3+6)+16*(3+6)]; + int analog_signal_index; - // Read 20 hex words, correct them using their Golay24 parity data. + analog_signal_index = 0; + + // we skip the status dibits that occur every 36 symbols + // the next status symbol comes in 14 dibits from here + // so we start counter at 36-14-1 = 21 + status_count = 21; + + // Read 20 hex words, correct them using their Golay 24 parity data. for (i=19; i>=0; i--) { - read_and_correct_hex_word (opts, state, hex, &status_count); + read_and_correct_hex_word (opts, state, hex, &status_count, analog_signal_array, &analog_signal_index); // Store the corrected hex word into the hex_data store: for (j=0; j<6; j++) { @@ -137,24 +249,57 @@ processHDU (dsd_opts * opts, dsd_state * state) } } - // Read the 16 parity hex word. These are used to FEC the 20 hex words using Reed-Solomon. for (i=15; i>=0; i--) { - read_and_correct_hex_word (opts, state, hex, &status_count); + read_and_correct_hex_word (opts, state, hex, &status_count, analog_signal_array, &analog_signal_index); // Store the corrected hex word into the hex_parity store: for (j=0; j<6; j++) { hex_parity[i][j] = hex[j]; } } + // Don't forget to mark the first element as the start of a new sequence + analog_signal_array[0].sequence_broken = 1; // Use the Reed-Solomon algorithm to correct the data. hex_data is modified in place irrecoverable_errors = check_and_fix_redsolomon_36_20_17((char*)hex_data, (char*)hex_parity); if (irrecoverable_errors != 0) { + // The hex words failed the Reed-Solomon check. There were too many errors. Still we can use this + // information to update an estimate of the BER. state->debug_header_critical_errors++; + + // We can correct (17-1)/2 = 8 errors. If we failed, it means that there were more than 8 errors in + // these 20+16 words. But take into account that each hex word was already error corrected with + // Golay 24, which can correct 3 bits on each sequence of (6+12) bits. We could say that there were + // 9 errors of 4 bits. + update_error_stats(&state->p25_heuristics, 20*6+16*6, 9*4); } + else + { + // The hex words passed the Reed-Solomon check. This means that very likely they are correct and we + // can trust that the digitizer did a good job with them. In other words, each analog value was + // correctly assigned to a dibit. This is extremely useful information for the digitizer and we are + // going to exploit it. + char fixed_parity[16*6]; + + // Correct the dibits that we did read according with the newly corrected hex_data values + correct_golay_dibits_6((char*)hex_data, 20, analog_signal_array); + + // Generate again the Reed-Solomon parity for the corrected data + encode_reedsolomon_36_20_17((char*)hex_data, fixed_parity); + + // Correct the dibits that we read according with the corrected parity values + correct_golay_dibits_6(fixed_parity, 16, analog_signal_array+20*(3+6)); + + // Now we have a bunch of dibits (composed of data and parity of different kinds) that we trust are all + // correct. We also keep a record of the analog values from where each dibit is coming from. + // This information is gold for the heuristics module. + contribute_to_heuristics(state->rf_mod, &(state->p25_heuristics), analog_signal_array, 20*(3+6)+16*(3+6)); + } + + // Now put the corrected data on the DSD structures mi[72] = 0; mfid[8] = 0; @@ -162,147 +307,145 @@ processHDU (dsd_opts * opts, dsd_state * state) kid[16] = 0; tgid[16] = 0; - // Now put the corrected data on the DSD structures + mi[ 0] = hex_data[19][0] + '0'; + mi[ 1] = hex_data[19][1] + '0'; + mi[ 2] = hex_data[19][2] + '0'; + mi[ 3] = hex_data[19][3] + '0'; + mi[ 4] = hex_data[19][4] + '0'; + mi[ 5] = hex_data[19][5] + '0'; - mi[ 0] = hex_data[19][0] + '0'; - mi[ 1] = hex_data[19][1] + '0'; - mi[ 2] = hex_data[19][2] + '0'; - mi[ 3] = hex_data[19][3] + '0'; - mi[ 4] = hex_data[19][4] + '0'; - mi[ 5] = hex_data[19][5] + '0'; + mi[ 6] = hex_data[18][0] + '0'; + mi[ 7] = hex_data[18][1] + '0'; + mi[ 8] = hex_data[18][2] + '0'; + mi[ 9] = hex_data[18][3] + '0'; + mi[10] = hex_data[18][4] + '0'; + mi[11] = hex_data[18][5] + '0'; - mi[ 6] = hex_data[18][0] + '0'; - mi[ 7] = hex_data[18][1] + '0'; - mi[ 8] = hex_data[18][2] + '0'; - mi[ 9] = hex_data[18][3] + '0'; - mi[10] = hex_data[18][4] + '0'; - mi[11] = hex_data[18][5] + '0'; + mi[12] = hex_data[17][0] + '0'; + mi[13] = hex_data[17][1] + '0'; + mi[14] = hex_data[17][2] + '0'; + mi[15] = hex_data[17][3] + '0'; + mi[16] = hex_data[17][4] + '0'; + mi[17] = hex_data[17][5] + '0'; - mi[12] = hex_data[17][0] + '0'; - mi[13] = hex_data[17][1] + '0'; - mi[14] = hex_data[17][2] + '0'; - mi[15] = hex_data[17][3] + '0'; - mi[16] = hex_data[17][4] + '0'; - mi[17] = hex_data[17][5] + '0'; + mi[18] = hex_data[16][0] + '0'; + mi[19] = hex_data[16][1] + '0'; + mi[20] = hex_data[16][2] + '0'; + mi[21] = hex_data[16][3] + '0'; + mi[22] = hex_data[16][4] + '0'; + mi[23] = hex_data[16][5] + '0'; - mi[18] = hex_data[16][0] + '0'; - mi[19] = hex_data[16][1] + '0'; - mi[20] = hex_data[16][2] + '0'; - mi[21] = hex_data[16][3] + '0'; - mi[22] = hex_data[16][4] + '0'; - mi[23] = hex_data[16][5] + '0'; + mi[24] = hex_data[15][0] + '0'; + mi[25] = hex_data[15][1] + '0'; + mi[26] = hex_data[15][2] + '0'; + mi[27] = hex_data[15][3] + '0'; + mi[28] = hex_data[15][4] + '0'; + mi[29] = hex_data[15][5] + '0'; - mi[24] = hex_data[15][0] + '0'; - mi[25] = hex_data[15][1] + '0'; - mi[26] = hex_data[15][2] + '0'; - mi[27] = hex_data[15][3] + '0'; - mi[28] = hex_data[15][4] + '0'; - mi[29] = hex_data[15][5] + '0'; + mi[30] = hex_data[14][0] + '0'; + mi[31] = hex_data[14][1] + '0'; + mi[32] = hex_data[14][2] + '0'; + mi[33] = hex_data[14][3] + '0'; + mi[34] = hex_data[14][4] + '0'; + mi[35] = hex_data[14][5] + '0'; - mi[30] = hex_data[14][0] + '0'; - mi[31] = hex_data[14][1] + '0'; - mi[32] = hex_data[14][2] + '0'; - mi[33] = hex_data[14][3] + '0'; - mi[34] = hex_data[14][4] + '0'; - mi[35] = hex_data[14][5] + '0'; + mi[36] = hex_data[13][0] + '0'; + mi[37] = hex_data[13][1] + '0'; + mi[38] = hex_data[13][2] + '0'; + mi[39] = hex_data[13][3] + '0'; + mi[40] = hex_data[13][4] + '0'; + mi[41] = hex_data[13][5] + '0'; - mi[36] = hex_data[13][0] + '0'; - mi[37] = hex_data[13][1] + '0'; - mi[38] = hex_data[13][2] + '0'; - mi[39] = hex_data[13][3] + '0'; - mi[40] = hex_data[13][4] + '0'; - mi[41] = hex_data[13][5] + '0'; + mi[42] = hex_data[12][0] + '0'; + mi[43] = hex_data[12][1] + '0'; + mi[44] = hex_data[12][2] + '0'; + mi[45] = hex_data[12][3] + '0'; + mi[46] = hex_data[12][4] + '0'; + mi[47] = hex_data[12][5] + '0'; - mi[42] = hex_data[12][0] + '0'; - mi[43] = hex_data[12][1] + '0'; - mi[44] = hex_data[12][2] + '0'; - mi[45] = hex_data[12][3] + '0'; - mi[46] = hex_data[12][4] + '0'; - mi[47] = hex_data[12][5] + '0'; + mi[48] = hex_data[11][0] + '0'; + mi[49] = hex_data[11][1] + '0'; + mi[50] = hex_data[11][2] + '0'; + mi[51] = hex_data[11][3] + '0'; + mi[52] = hex_data[11][4] + '0'; + mi[53] = hex_data[11][5] + '0'; - mi[48] = hex_data[11][0] + '0'; - mi[49] = hex_data[11][1] + '0'; - mi[50] = hex_data[11][2] + '0'; - mi[51] = hex_data[11][3] + '0'; - mi[52] = hex_data[11][4] + '0'; - mi[53] = hex_data[11][5] + '0'; + mi[54] = hex_data[10][0] + '0'; + mi[55] = hex_data[10][1] + '0'; + mi[56] = hex_data[10][2] + '0'; + mi[57] = hex_data[10][3] + '0'; + mi[58] = hex_data[10][4] + '0'; + mi[59] = hex_data[10][5] + '0'; - mi[54] = hex_data[10][0] + '0'; - mi[55] = hex_data[10][1] + '0'; - mi[56] = hex_data[10][2] + '0'; - mi[57] = hex_data[10][3] + '0'; - mi[58] = hex_data[10][4] + '0'; - mi[59] = hex_data[10][5] + '0'; + mi[60] = hex_data[ 9][0] + '0'; + mi[61] = hex_data[ 9][1] + '0'; + mi[62] = hex_data[ 9][2] + '0'; + mi[63] = hex_data[ 9][3] + '0'; + mi[64] = hex_data[ 9][4] + '0'; + mi[65] = hex_data[ 9][5] + '0'; - mi[60] = hex_data[9][0] + '0'; - mi[61] = hex_data[9][1] + '0'; - mi[62] = hex_data[9][2] + '0'; - mi[63] = hex_data[9][3] + '0'; - mi[64] = hex_data[9][4] + '0'; - mi[65] = hex_data[9][5] + '0'; + mi[66] = hex_data[ 8][0] + '0'; + mi[67] = hex_data[ 8][1] + '0'; + mi[68] = hex_data[ 8][2] + '0'; + mi[69] = hex_data[ 8][3] + '0'; + mi[70] = hex_data[ 8][4] + '0'; + mi[71] = hex_data[ 8][5] + '0'; - mi[66] = hex_data[8][0] + '0'; - mi[67] = hex_data[8][1] + '0'; - mi[68] = hex_data[8][2] + '0'; - mi[69] = hex_data[8][3] + '0'; - mi[70] = hex_data[8][4] + '0'; - mi[71] = hex_data[8][5] + '0'; + mfid[0] = hex_data[ 7][0] + '0'; + mfid[1] = hex_data[ 7][1] + '0'; + mfid[2] = hex_data[ 7][2] + '0'; + mfid[3] = hex_data[ 7][3] + '0'; + mfid[4] = hex_data[ 7][4] + '0'; + mfid[5] = hex_data[ 7][5] + '0'; - mfid[0] = hex_data[7][0] + '0'; - mfid[1] = hex_data[7][1] + '0'; - mfid[2] = hex_data[7][2] + '0'; - mfid[3] = hex_data[7][3] + '0'; - mfid[4] = hex_data[7][4] + '0'; - mfid[5] = hex_data[7][5] + '0'; + mfid[6] = hex_data[ 6][0] + '0'; + mfid[7] = hex_data[ 6][1] + '0'; + algid[0] = hex_data[ 6][2] + '0'; // The important algorithm ID. This indicates whether the data is + algid[1] = hex_data[ 6][3] + '0'; // encrypted and if so what is the encryption algorithm used. + algid[2] = hex_data[ 6][4] + '0'; // A code 0x80 here means that the data is unencrypted. + algid[3] = hex_data[ 6][5] + '0'; - mfid[6] = hex_data[6][0] + '0'; - mfid[7] = hex_data[6][1] + '0'; - algid[0] = hex_data[6][2] + '0'; // The important algorithm ID. This indicates whether the data is - algid[1] = hex_data[6][3] + '0'; // encrypted and if so what is the encryption algorithm used. - algid[2] = hex_data[6][4] + '0'; // A code 0x80 here means that the data is unencrypted. - algid[3] = hex_data[6][5] + '0'; + algid[4] = hex_data[ 5][0] + '0'; + algid[5] = hex_data[ 5][1] + '0'; + algid[6] = hex_data[ 5][2] + '0'; + algid[7] = hex_data[ 5][3] + '0'; + kid[ 0] = hex_data[ 5][4] + '0'; + kid[ 1] = hex_data[ 5][5] + '0'; - algid[4] = hex_data[5][0] + '0'; - algid[5] = hex_data[5][1] + '0'; - algid[6] = hex_data[5][2] + '0'; - algid[7] = hex_data[5][3] + '0'; - kid[ 0] = hex_data[5][4] + '0'; - kid[ 1] = hex_data[5][5] + '0'; + kid[ 2] = hex_data[ 4][0] + '0'; // The encryption key ID + kid[ 3] = hex_data[ 4][1] + '0'; + kid[ 4] = hex_data[ 4][2] + '0'; + kid[ 5] = hex_data[ 4][3] + '0'; + kid[ 6] = hex_data[ 4][4] + '0'; + kid[ 7] = hex_data[ 4][5] + '0'; - kid[ 2] = hex_data[4][0] + '0'; // The encryption key ID - kid[ 3] = hex_data[4][1] + '0'; - kid[ 4] = hex_data[4][2] + '0'; - kid[ 5] = hex_data[4][3] + '0'; - kid[ 6] = hex_data[4][4] + '0'; - kid[ 7] = hex_data[4][5] + '0'; + kid[ 8] = hex_data[ 3][0] + '0'; + kid[ 9] = hex_data[ 3][1] + '0'; + kid[10] = hex_data[ 3][2] + '0'; + kid[11] = hex_data[ 3][3] + '0'; + kid[12] = hex_data[ 3][4] + '0'; + kid[13] = hex_data[ 3][5] + '0'; - kid[ 8] = hex_data[3][0] + '0'; - kid[ 9] = hex_data[3][1] + '0'; - kid[10] = hex_data[3][2] + '0'; - kid[11] = hex_data[3][3] + '0'; - kid[12] = hex_data[3][4] + '0'; - kid[13] = hex_data[3][5] + '0'; + kid[14] = hex_data[ 2][0] + '0'; + kid[15] = hex_data[ 2][1] + '0'; + tgid[ 0] = hex_data[ 2][2] + '0'; // Talk group ID + tgid[ 1] = hex_data[ 2][3] + '0'; + tgid[ 2] = hex_data[ 2][4] + '0'; + tgid[ 3] = hex_data[ 2][5] + '0'; - kid[14] = hex_data[2][0] + '0'; - kid[15] = hex_data[2][1] + '0'; - tgid[ 0] = hex_data[2][2] + '0'; // Talk group ID - tgid[ 1] = hex_data[2][3] + '0'; - tgid[ 2] = hex_data[2][4] + '0'; - tgid[ 3] = hex_data[2][5] + '0'; + tgid[ 4] = hex_data[ 1][0] + '0'; + tgid[ 5] = hex_data[ 1][1] + '0'; + tgid[ 6] = hex_data[ 1][2] + '0'; + tgid[ 7] = hex_data[ 1][3] + '0'; + tgid[ 8] = hex_data[ 1][4] + '0'; + tgid[ 9] = hex_data[ 1][5] + '0'; - tgid[ 4] = hex_data[1][0] + '0'; - tgid[ 5] = hex_data[1][1] + '0'; - tgid[ 6] = hex_data[1][2] + '0'; - tgid[ 7] = hex_data[1][3] + '0'; - tgid[ 8] = hex_data[1][4] + '0'; - tgid[ 9] = hex_data[1][5] + '0'; - - tgid[10] = hex_data[0][0] + '0'; - tgid[11] = hex_data[0][1] + '0'; - tgid[12] = hex_data[0][2] + '0'; - tgid[13] = hex_data[0][3] + '0'; - tgid[14] = hex_data[0][4] + '0'; - tgid[15] = hex_data[0][5] + '0'; + tgid[10] = hex_data[ 0][0] + '0'; + tgid[11] = hex_data[ 0][1] + '0'; + tgid[12] = hex_data[ 0][2] + '0'; + tgid[13] = hex_data[ 0][3] + '0'; + tgid[14] = hex_data[ 0][4] + '0'; + tgid[15] = hex_data[ 0][5] + '0'; state->p25kid = strtol(kid, NULL, 2); diff --git a/p25p1_hdu.h b/p25p1_hdu.h index b5ee4d3..e2be95e 100644 --- a/p25p1_hdu.h +++ b/p25p1_hdu.h @@ -1,15 +1,73 @@ -#ifndef __P25P1_HDU_H__ -#define __P25P1_HDU_H__ +#ifndef P25P1_HDU_H_9f95c3a5072842e8aaf94444e1452d20 +#define P25P1_HDU_H_9f95c3a5072842e8aaf94444e1452d20 + + +#include "p25p1_heuristics.h" /** - * Reads a dibit keeping track of the status dibits that shows up every 70 bits + * Reads a dibit (two bits) from the stream of data. Takes into account the periodic occurrence of status + * bits that show up every 36 dibits. Status bits are discarded. + * \param opts A pointer the the DSD options. + * \param state A pointer the the DSD state structure. + * \param output A pointer to be filled with the dibit read. Two bytes used for each dibit. + * \param status_count Variable used to keep track of the status symbols in the dibit stream. There is one + * status every 36 dibits. With this counter we can skip the status. + * \param analog_signal A pointer with the actual analog value read from the input signal and that has been + * interpreted as the dibit we are returning in output. + * \param did_read_status Address were a boolean is returned. This is set to true when one status symbol was + * read (and skipped). This indicates that the sequence on dibits has been broken and is used by the P25 + * heuristics. */ -void read_dibit (dsd_opts* opts, dsd_state* state, char* output, int* status_count); +int read_dibit (dsd_opts* opts, dsd_state* state, char* output, int* status_count, int* analog_signal, + int* did_read_status); /** - * Read an "hex" word. An hex word is made up of 3 dibits. Also keeps track of the status dibits. + * Reads a number of dibits and stores its value together with the actual analog value that has been + * intrepreted as the dibit into an AnalogSignal structure. This is used later in the P25 heuristics module + * to improve the accuracy of the digitizer. + * \param opts A pointer the the DSD options. + * \param state A pointer the the DSD state structure. + * \param output A pointer to be filled with the dibits read. + * \param count The number of bits to read (remember: 1 dibit = 2 bits). + * \param status_count Variable used to keep track of the status symbols in the dibit stream. There is one + * status every 36 dibits. With this counter we can skip the status. + * \param analog_signal_array The pointer to the start of a sequence of AnalogSignal structures. The + * information is updated for each dibit read. + * \param analog_signal_index The actual index into the AnalogSignal array. This is increased here wich each + * dibit read. */ -void read_hex (dsd_opts* opts, dsd_state* state, char* hex, int* status_count); +void read_dibit_update_analog_data (dsd_opts* opts, dsd_state* state, char* buffer, unsigned int count, + int* status_count, AnalogSignal* analog_signal_array, int* analog_signal_index); -#endif // __P25P1_HDU_H__ +/** + * Reads a word, made up of length bits or length/2 dibits. Also keeps track of the status dibits. + */ +void read_word (dsd_opts* opts, dsd_state* state, char* word, unsigned int length, int* status_count, + AnalogSignal* analog_signal_array, int* analog_signal_index); + +/** + * Reads 4 bits from the stream of data. Those are the parity bits that follow each hex word. + */ +void read_hamm_parity (dsd_opts* opts, dsd_state* state, char* parity, int* status_count, + AnalogSignal* analog_signal_array, int* analog_signal_index); + +/** + * Reads 12 bits from the stream of data. Those are the extended Golay parity bits that follow a word of data. + */ +void read_golay24_parity (dsd_opts* opts, dsd_state* state, char* parity, int* status_count, AnalogSignal* analog_signal_array, int* analog_signal_index); + +/** + * Reads bits from the data stream that should all be zeros. This is valuable information for the + * heuristics module and we update it. + * \param opts A pointer the the DSD options. + * \param state A pointer the the DSD state structure. + * \param analog_signal_array The pointer to the start of a sequence of AnalogSignal structures. + * \param length Number of bits to read. + * \param status_count Variable used to keep track of the status symbols in the dibit stream. + * \param new_sequence Bool used to update the sequence_broken value of the first AnalogSignal element. + */ +void read_zeros(dsd_opts* opts, dsd_state* state, AnalogSignal* analog_signal_array, unsigned int length, + int* status_count, int new_sequence); + +#endif // P25P1_HDU_H_9f95c3a5072842e8aaf94444e1452d20 diff --git a/p25p1_heuristics.c b/p25p1_heuristics.c new file mode 100644 index 0000000..ea48d5e --- /dev/null +++ b/p25p1_heuristics.c @@ -0,0 +1,386 @@ + +#define _USE_MATH_DEFINES +#include + +#include "dsd.h" + +#include "p25p1_heuristics.h" + +/** + * This module is dedicated to improve the accuracy of the digitizer. The digitizer is the piece of code that + * translates an analog value to an actual symbol, in the case of P25, a dibit. + * It implements a simple Gaussian classifier. It's based in the assumption that the analog values from the + * signal follow normal distributions, one single distribution for each symbol. + * Analog values for the dibit "0" will fit into a Gaussian bell curve with a characteristic mean and std + * distribution and the same goes for dibits "1", "2" and "3." + * Hopefully those bell curves are well separated from each other so we can accurately discriminate dibits. + * If we could model the Gaussian of each dibit, then given an analog value, the dibit whose Gaussian fits + * better is the most likely interpretation for that value. By better fit we can calculate the PDF + * (probability density function) for the Gaussian, the one with the highest value is the best fit. + * + * The approach followed here to model the Gaussian for each dibit is to use the error corrected information + * as precise oracles. P25 uses strong error correction, some dibits are doubly protected by Hamming/Golay + * and powerful Reed-Solomon codes. If a sequence of dibits clears the last Reed-Solomon check, we can be + * quite confident that those values are correct. We can use the analog values for those cleared dibits to + * calculate mean and std deviation of our Gaussians. With this we are ready to calculate the PDF of a new + * unknown analog value when required. + * Values that don't clear the Reed-Solomon check are discarded. + * This implementation uses a circular buffer to keep track of the N latest cleared analog dibits so we can + * adapt to changes in the signal. + * A modification was made to improve results for C4FM signals. See next block comment. + */ + +/** + * In the C4FM P25 recorded files from the "samples" repository, it can be observed that there is a + * correlation between the correct dibit associated for a given analog value and the value of the previous + * dibit. For instance, in one P25 recording, the dibits "0" come with an average analog signal of + * 3829 when the previous dibit was also "0," but if the previous dibit was a "3" then the average + * analog signal is 6875. These are the mean and std deviations for the full 4x4 combinations of previous and + * current dibits: + * + * 00: count: 200 mean: 3829.12 sd: 540.43 <- + * 01: count: 200 mean: 13352.45 sd: 659.74 + * 02: count: 200 mean: -5238.56 sd: 1254.70 + * 03: count: 200 mean: -13776.50 sd: 307.41 + * 10: count: 200 mean: 3077.74 sd: 1059.00 + * 11: count: 200 mean: 11935.11 sd: 776.20 + * 12: count: 200 mean: -6079.46 sd: 1003.94 + * 13: count: 200 mean: -13845.43 sd: 264.42 + * 20: count: 200 mean: 5574.33 sd: 1414.71 + * 21: count: 200 mean: 13687.75 sd: 727.68 + * 22: count: 200 mean: -4753.38 sd: 765.95 + * 23: count: 200 mean: -12342.17 sd: 1372.77 + * 30: count: 200 mean: 6875.23 sd: 1837.38 <- + * 31: count: 200 mean: 14527.99 sd: 406.85 + * 32: count: 200 mean: -3317.61 sd: 1089.02 + * 33: count: 200 mean: -12576.08 sd: 1161.77 + * || | | | + * || | | \_std deviation + * || | | + * || | \_mean of the current dibit + * || | + * || \_number of dibits used to calculate mean and std deviation + * || + * |\_current dibit + * | + * \_previous dibit + * + * This effect is not observed on QPSK or GFSK signals, there the mean values are quite consistent regardless + * of the previous dibit. + * + * The following define enables taking the previous dibit into account for C4FM signals. Comment out + * to disable. + */ +#define USE_PREVIOUS_DIBIT + +/** + * There is a minimum of cleared analog values we need to produce a meaningful mean and std deviation. + */ +#define MIN_ELEMENTS_FOR_HEURISTICS 10 + + +//Uncomment to disable the behaviour of this module. +//#define DISABLE_HEURISTICS + +/** + * The value of the previous dibit is only taken into account on the C4FM modulation. QPSK and GFSK are + * not improved by this technique. + */ +static int use_previous_dibit(int rf_mod) +{ + // 0: C4FM modulation + // 1: QPSK modulation + // 2: GFSK modulation + + // Use previoud dibit information when on C4FM + return (rf_mod == 0)? 1 : 0; +} + +/** + * Update the model of a symbol's Gaussian with new information. + * \param heuristics Pointer to the P25Heuristics module with all the needed state information. + * \param previous_dibit The cleared previous dibit value. + * \param original_dibit The current dibit as it was interpreted initially. + * \param dibit The current dibit. Will be different from original_dibit if the FEC fixed it. + * \param analog_value The actual analog signal value from which the original_dibit was derived. + */ +static void update_p25_heuristics(P25Heuristics* heuristics, int previous_dibit, int original_dibit, int dibit, int analog_value) +{ + float mean; + int old_value; + float old_mean; + + SymbolHeuristics* sh; + int number_errors; + +#ifndef USE_PREVIOUS_DIBIT + previous_dibit = 0; +#endif + + // Locate the Gaussian (SymbolHeuristics structure) we are going to update + sh = &(heuristics->symbols[previous_dibit][dibit]); + + // Update the circular buffers of values + old_value = sh->values[sh->index]; + old_mean = sh->means[sh->index]; + + // Update the BER statistics + number_errors = 0; + if (original_dibit != dibit) { + if ((original_dibit == 0 && dibit == 3) || (original_dibit == 3 && dibit == 0) || + (original_dibit == 1 && dibit == 2) || (original_dibit == 2 && dibit == 1)) { + // Interpreting a "00" as "11", "11" as "00", "01" as "10" or "10" as "01" counts as 2 errors + number_errors = 2; + } else { + // The other 12 combinations count as 1 error. + number_errors = 1; + } + } + update_error_stats(heuristics, 2, number_errors); + + // Update the running mean and variance. This is to calculate the PDF faster when required + if (sh->count >= HEURISTICS_SIZE) { + sh->sum -= old_value; + sh->var_sum -= (((float)old_value) - old_mean) * (((float)old_value) - old_mean); + } + sh->sum += analog_value; + + sh->values[sh->index] = analog_value; + if (sh->count < HEURISTICS_SIZE) { + sh->count++; + } + mean = sh->sum / ((float)sh->count); + sh->means[sh->index] = mean; + if (sh->index >= (HEURISTICS_SIZE-1)) { + sh->index = 0; + } else { + sh->index++; + } + + sh->var_sum += (((float)analog_value) - mean) * (((float)analog_value) - mean); +} + +void contribute_to_heuristics(int rf_mod, P25Heuristics* heuristics, AnalogSignal* analog_signal_array, int count) +{ + int i; + int use_prev_dibit; + +#ifdef USE_PREVIOUS_DIBIT + use_prev_dibit = use_previous_dibit(rf_mod); +#else + use_prev_dibit = 0; +#endif + + for (i=0; icount = 0; + sh->index = 0; + sh->sum = 0; + sh->var_sum = 0; +} + +void initialize_p25_heuristics(P25Heuristics* heuristics) +{ + int i, j; + for (i=0; i<4; i++) { + for (j=0; j<4; j++) { + initialize_symbol_heuristics(&(heuristics->symbols[i][j])); + } + } + heuristics->bit_count = 0; + heuristics->bit_error_count = 0; +} + +/** + * Important method to calculate the PDF (probability density function) of the Gaussian. + * TODO: improve performance. Since we are calculating this value to compare it with other PDF we can + * simplify very much. We don't really need to know the actual PDF value, just which Gaussian's got the + * highest PDF, which is a simpler problem. + */ +static float evaluate_pdf(SymbolHeuristics* se, int value) +{ + float x = (se->count*((float)value) - se->sum); + float y = -0.5F*x*x/(se->count*se->var_sum); + float pdf = sqrtf(se->count / se->var_sum) * expf(y) / sqrtf(2.0F * ((float) M_PI)); + + return pdf; +} + + +/** + * Logging of the internal PDF values for a given analog value and previous dibit. + */ +static void debug_log_pdf(P25Heuristics* heuristics, int previous_dibit, int analog_value) +{ + int i; + float pdfs[4]; + + for (i=0; i<4; i++) { + pdfs[i] = evaluate_pdf(&(heuristics->symbols[previous_dibit][i]), analog_value); + } + + printf("v: %i, (%e, %e, %e, %e)\n", analog_value, pdfs[0], pdfs[1], pdfs[2], pdfs[3]); +} + +int estimate_symbol(int rf_mod, P25Heuristics* heuristics, int previous_dibit, int analog_value, int* dibit) +{ + int valid; + int i; + float pdfs[4]; + + +#ifdef USE_PREVIOUS_DIBIT + int use_prev_dibit = use_previous_dibit(rf_mod); + + if (use_prev_dibit == 0) + { + // Ignore + previous_dibit = 0; + } +#else + // Use previous_dibit as it comes. +#endif + + valid = 1; + + // Check if we have enough values to model the Gaussians for each symbol involved. + for (i=0; i<4; i++) { + if (heuristics->symbols[previous_dibit][i].count >= MIN_ELEMENTS_FOR_HEURISTICS) { + pdfs[i] = evaluate_pdf(&(heuristics->symbols[previous_dibit][i]), analog_value); + } else { + // Not enough data, we don't trust this result + valid = 0; + break; + } + } + + if (valid) { + // Find the highest pdf + int max_index; + float max; + + max_index = 0; + max = pdfs[0]; + for (i=1; i<4; i++) { + if (pdfs[i] > max) { + max_index = i; + max = pdfs[i]; + } + } + + // The symbol is the one with the highest pdf + *dibit = max_index; + } + +#ifdef DISABLE_HEURISTICS + valid = 0; +#endif + + return valid; +} + +/** + * Logs the internal state of the heuristic's state. Good for debugging. + */ +static void debug_print_symbol_heuristics(int previous_dibit, int dibit, SymbolHeuristics* sh) +{ + float mean, sd; + int k; + int n; + + n = sh->count; + if (n == 0) + { + mean = 0; + sd = 0; + } + else + { + mean = sh->sum/n; + sd = sqrtf(sh->var_sum / ((float) n)); + } + printf("%i%i: count: %2i mean: % 10.2f sd: % 10.2f", previous_dibit, dibit, sh->count, mean, sd); + /* + printf("("); + for (k=0; kvalues[k]); + } + printf(")"); + */ + printf("\n"); + +} + +void debug_print_heuristics(P25Heuristics* heuristics) +{ + int i,j; + + printf("\n"); + + for(i=0; i<4; i++) + { + for(j=0; j<4; j++) + { + debug_print_symbol_heuristics(i, j, &(heuristics->symbols[i][j])); + } + } +} + +void update_error_stats(P25Heuristics* heuristics, int bits, int errors) +{ + heuristics->bit_count += bits; + heuristics->bit_error_count += errors; + + // Normalize to avoid overflow in the counters + if ((heuristics->bit_count & 1) == 0 && (heuristics->bit_error_count & 1) == 0) { + // We can divide both values by 2 safely. We just care about their ratio, not the actual value + heuristics->bit_count >>= 1; + heuristics->bit_error_count >>= 1; + } +} + +float get_P25_BER_estimate(P25Heuristics* heuristics) +{ + float ber; + if (heuristics->bit_count == 0) { + ber = 0.0F; + } else { + ber = ((float)heuristics->bit_error_count) * 100.0F / ((float)heuristics->bit_count); + } + return ber; +} diff --git a/p25p1_heuristics.h b/p25p1_heuristics.h new file mode 100644 index 0000000..a424596 --- /dev/null +++ b/p25p1_heuristics.h @@ -0,0 +1,91 @@ + +#ifndef P25P1_HEURISTICS_H_030dd3530b7546abbb56f8dd1e66a2f6 +#define P25P1_HEURISTICS_H_030dd3530b7546abbb56f8dd1e66a2f6 + +#define HEURISTICS_SIZE 200 +typedef struct +{ + int values[HEURISTICS_SIZE]; + float means[HEURISTICS_SIZE]; + int index; + int count; + float sum; + float var_sum; +} SymbolHeuristics; + +typedef struct +{ + unsigned int bit_count; + unsigned int bit_error_count; + SymbolHeuristics symbols[4][4]; +} P25Heuristics; + +typedef struct +{ + int value; + int dibit; + int corrected_dibit; + int sequence_broken; +} AnalogSignal; + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * Initializes the heuristics state. + * \param heuristics The P25Heuristics structure to initialize. + */ +void initialize_p25_heuristics(P25Heuristics* heuristics); + +/** + * Important method that estimates the most likely symbol for a given analog signal value and previous dibit. + * This is called by the digitizer. + * \param rf_mod Indicates the modulation used. The previous dibit is only used on C4FM. + * \param heuristics Pointer to the P25Heuristics module with all the needed state information. + * \param previous_dibit The previous dibit. + * \param analog_value The signal's analog value we want to interpret as a dibit. + * \param dibit Address were to store the estimated dibit. + * \return A boolean set to true if we are able to estimate a dibit. The reason why we might not be able + * to estimate it is because we don't have enough information to model the Gaussians (not enough data + * has been passed to contribute_to_heuristics). + */ +int estimate_symbol(int rf_mod, P25Heuristics* heuristics, int previous_dibit, int analog_value, int* dibit); + +/** + * Log some useful information on the heuristics state. + */ +void debug_print_heuristics(P25Heuristics* heuristics); + +/** + * This method contributes valuable information from dibits whose value we are confident is correct. We take + * the dibits and corresponding analog signal values to model the Gaussians for each dibit (and previous + * dibit if enabled). + * \param rf_mod Indicates the modulation used. The previous dibit is only used on C4FM. + * \param heuristics Pointer to the P25Heuristics module with all the needed state information. + * \param analog_signal_array Sequence of AnalogSignal which contain the cleared dibits and analog values. + * \param count number of cleared dibits passed (= number of elements to use from analog_signal_array). + */ +void contribute_to_heuristics(int rf_mod, P25Heuristics* heuristics, AnalogSignal* analog_signal_array, int count); + +/** + * Updates the estimate for the BER (bit error rate). Mind this is method is not called for every single + * bit in the data stream but only for those bits over which we have an estimate of its error rate, + * specifically the bits that are protected by Reed-Solomon codes. + * \param heuristics The heuristics state. + * \param bits The number of bits we have read. + * \param errors The number of errors we estimate in those bits. + */ +void update_error_stats(P25Heuristics* heuristics, int bits, int errors); + +/** + * Returns the estimate for the BER (bit error rate). + * \return The estimated BER. This is just the percentage of errors over the processed bits. + */ +float get_P25_BER_estimate(P25Heuristics* heuristics); + +#ifdef __cplusplus +} +#endif + +#endif // P25P1_HEURISTICS_H_030dd3530b7546abbb56f8dd1e66a2f6 diff --git a/p25p1_ldu.c b/p25p1_ldu.c index 990e229..c7dc85b 100644 --- a/p25p1_ldu.c +++ b/p25p1_ldu.c @@ -2,8 +2,65 @@ #include "dsd.h" #include "p25p1_const.h" #include "p25p1_hdu.h" +#include "p25p1_check_ldu.h" +#include "p25p1_heuristics.h" + +#ifdef TRACE_DSD +static void +debug_write_label_imbe(dsd_state* state, unsigned int cc, int bitindex, char bit) +{ + float left, right; + + if (state->debug_label_imbe_file == NULL) + { + state->debug_label_imbe_file = fopen ("pp_label_imbe.txt", "w"); + } + left = (state->debug_sample_index-10) / 48000.0F; + right = (state->debug_sample_index) / 48000.0F; + fprintf(state->debug_label_imbe_file, "%f\t%f\tC_%i[%i]=%c\n", left, right, cc, bitindex, (bit + '0')); +} +#endif + +/** + * Logs the IMBE's c0-c6 words. + */ +static void +debug_log_imbe(char imbe_fr[8][23]) +{ + int i, j; + printf(" "); + + for (j=0; j<4; j++) + { + printf("{"); + for (i=0; i<23; i++) + { + if (i>0) + { + printf(", "); + } + printf("%c", (imbe_fr[j][i] + '0')); + } + printf("}; "); + } + + for (j=4; j<7; j++) + { + printf("{"); + for (i=0; i<15; i++) + { + if (i>0) + { + printf(", "); + } + printf("%c", (imbe_fr[j][i] + '0')); + } + printf("}; "); + } + + printf("\n"); +} -// separate imbe frames and deinterleave void process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count) { @@ -16,13 +73,25 @@ process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count) y = iY; z = iZ; +#ifdef TRACE_DSD + state->debug_prefix = 'I'; +#endif + for (j = 0; j < 72; j++) { if (*status_count == 35) { + // Skip the status symbol +#ifdef TRACE_DSD + state->debug_prefix = 's'; +#endif status = getDibit (opts, state); // TODO: do something useful with the status bits... *status_count = 1; + +#ifdef TRACE_DSD + state->debug_prefix = 'I'; +#endif } else { @@ -31,77 +100,170 @@ process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count) dibit = getDibit (opts, state); imbe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 imbe_fr[*y][*z] = (1 & dibit); // bit 0 + +#ifdef TRACE_DSD + if (*w == 0) { + debug_write_label_imbe(state, 0, *x, (1 & (dibit >> 1))); + } + if (*y == 0) { + debug_write_label_imbe(state, 0, *z, (1 & dibit)); + } +#endif + w++; x++; y++; z++; } +#ifdef TRACE_DSD + state->debug_prefix = '\0'; +#endif + if (state->p25kid == 0 || opts->unmute_encrypted_p25 == 1) { - processMbeFrame (opts, state, imbe_fr, NULL, NULL); + { + // Check for a non-standard c0 transmitted + // This is explained here: https://github.com/szechyjs/dsd/issues/24 + char non_standard_word[23] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}; + int match = 1; + unsigned int i; + for (i=0; i<23; i++) { + if (imbe_fr[0][i] != non_standard_word[i]) { + match = 0; + break; + } + } + + if (match) { + // Skip this particular value. If we let it pass it will be signaled as an erroneus IMBE + printf("(Non-standard IMBE c0 detected, skipped)"); + } else { + processMbeFrame (opts, state, imbe_fr, NULL, NULL); + } + } } } -/** - * Read 4 bits from the stream of data. Those are the parity bits that follow each hex word. - */ -static void -read_hamm_parity (dsd_opts* opts, dsd_state* state, char* parity, int* status_count) -{ - // Read 2 dibits = read 4 bits. - read_dibit(opts, state, parity, status_count); - read_dibit(opts, state, parity + 2, status_count); -} +// Uncomment this line for verbose information on the error correction of the LDU bits. +//#define LDU_DEBUG -//#define __LDU_DEBUG__ - -/** - * Read an hex word, its parity bits and attempts to error correct it using the Hamming algorithm. - */ void -read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count) +read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count, + AnalogSignal* analog_signal_array, int* analog_signal_index) { char parity[4]; - int i; + int error_count; // Read the hex word - read_hex (opts, state, hex, status_count); + read_word (opts, state, hex, 6, status_count, analog_signal_array, analog_signal_index); // Read the parity - read_hamm_parity (opts, state, parity, status_count); + read_hamm_parity (opts, state, parity, status_count, analog_signal_array, analog_signal_index); -#ifdef __LDU_DEBUG__ +#ifdef LDU_DEBUG printf("["); - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) + { printf("%c", (hex[i] == 1)? 'X' : ' '); - } + } printf("-"); - for (i = 0; i < 4; i++) { + for (i = 0; i < 4; i++) + { printf("%c", (parity[i] == 1)? 'X' : ' '); - } + } printf("]"); #endif // Use Hamming to error correct the hex word - int error_count = check_and_fix_hamming_10_12_13(hex, parity); + error_count = check_and_fix_hamming_10_6_3(hex, parity); - if (error_count == 1) { + if (error_count == 1) + { state->debug_header_errors++; - } else if (error_count ==2) { + } + else if (error_count ==2) + { state->debug_header_critical_errors++; - } + } -#ifdef __LDU_DEBUG__ +#ifdef LDU_DEBUG printf(" -> ["); - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) + { printf("%c", (hex[i] == 1)? 'X' : ' '); - } + } printf("]"); - if (error_count == 1) { + if (error_count == 1) + { printf(" fixed!"); - } else if (error_count ==2) { + } + else if (error_count ==2) + { printf(" IRRECOVERABLE"); - } + } printf("\n"); #endif } + +void +correct_hamming_dibits(char* data, int count, AnalogSignal* analog_signal_array) +{ + char parity[4]; + int i, j; + int analog_signal_index; + + analog_signal_index = 0; + + for (i=count-1; i>=0; i--) + { + // Take the next 3 dibits (1 hex word) as they are + for (j=0; j<6; j+=2) // 3 iterations -> 3 dibits + { + int dibit = (data[i*6+j] << 1) | data[i*6+j+1]; + // This dibit is the correct value we should have read in the first place + analog_signal_array[analog_signal_index].corrected_dibit = dibit; + +#ifdef HEURISTICS_DEBUG + if (analog_signal_array[analog_signal_index].dibit != dibit) + { + printf("LDU word corrected from %i to %i, analog value %i\n", + analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value); + } +#endif + + analog_signal_index++; + } + + // The next two dibits are calculated has the hamming parity of the hex word + encode_hamming_10_6_3(data+i*6, parity); + + for (j=0; j<4; j+=2) // 2 iterations -> 2 dibits + { + int dibit = (parity[j] << 1) | parity[j+1]; + // Again, this dibit is the correct value we should have read in the first place + analog_signal_array[analog_signal_index].corrected_dibit = dibit; + +#ifdef HEURISTICS_DEBUG + if (analog_signal_array[analog_signal_index].dibit != dibit) + { + printf("LDU-HM parity corrected from %i to %i, analog value %i\n", + analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value); + } +#endif + + analog_signal_index++; + } + } +} + +void +debug_ldu_header(dsd_state* state) +{ +#ifdef TRACE_DSD + float s = state->debug_sample_index / 48000.0F; + printf("Start of LDU at sample %f\n", s); +#endif + + debug_print_heuristics(&state->p25_heuristics); +} + diff --git a/p25p1_ldu.h b/p25p1_ldu.h index fa73a19..eed8b70 100644 --- a/p25p1_ldu.h +++ b/p25p1_ldu.h @@ -1,18 +1,49 @@ -#ifndef __P25P1_LDU_H__ -#define __P25P1_LDU_H__ +#ifndef P25P1_LDU_H_a3c417fcb7804991b0e6d828066bd133 +#define P25P1_LDU_H_a3c417fcb7804991b0e6d828066bd133 #include "dsd.h" -#include "p25p1_const.h" -// separate imbe frames and deinterleave -void -process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count); +#include "p25p1_hdu.h" +#include "p25p1_const.h" +#include "p25p1_heuristics.h" /** - * Read an hex word, its parity bits and attempts to error correct it using the Hamming algorithm. + * Separate imbe frames and deinterleave. + * This important methods read the IMBE data from the stream and passes it to the vocoder to produce audio. + * \param opts The DSD options. + * \param state The DSD state. + * \status_count An index that allows us to skip the status words interleaved every 36 dibit in the data + * stream. */ -void -read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count); +void process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count); -#endif // __P25P1_LDU_H__ +/** + * Reads an hex word, its parity bits and attempts to error correct it using the Hamming FEC. + * \param opts The DSD options. + * \param state The DSD state. + * \param hex Pointer where to store the read hex word. Six bytes, one per bit. + * \param status_count An index that allows us to skip the status words interleaved every 36 dibit in the data + * stream. + * \param analog_singal_array Pointer to a sequence of AnalogSignal elements. + * \param analog_signal_index The current index in the analog_singal_array. This value is increased on each + * dibit read. + */ +void read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count, + AnalogSignal* analog_signal_array, int* analog_signal_index); + +/** + * Correct the information in analog_signal_array according with the content of data, which has been + * error corrected and should be valid. + * \param Dibits that have already been error corrected and we trust are correct. + * \count Number of dibits. + * \param analog_signal_array Pointer to a sequence of AnalogSignal elements, as many as the value of count. + */ +void correct_hamming_dibits(char* hex_data, int hex_count, AnalogSignal* analog_signal_array); + +/** + * Logs some debug info. + */ +void debug_ldu_header(dsd_state* state); + +#endif // P25P1_LDU_H_a3c417fcb7804991b0e6d828066bd133 diff --git a/p25p1_ldu1.c b/p25p1_ldu1.c index 99060d7..fcafbfd 100644 --- a/p25p1_ldu1.c +++ b/p25p1_ldu1.c @@ -20,14 +20,14 @@ #include "p25p1_ldu.h" #include "p25p1_check_ldu.h" - +#include "p25p1_hdu.h" void processLDU1 (dsd_opts* opts, dsd_state* state) { // extracts IMBE frames from LDU frame - int i, j, k, dibit; + int i; char lcformat[9], mfid[9], lcinfo[57]; char lsd1[9], lsd2[9]; @@ -38,15 +38,15 @@ processLDU1 (dsd_opts* opts, dsd_state* state) int irrecoverable_errors; - lcformat[8] = 0; - mfid[8] = 0; - lcinfo[56] = 0; - lsd1[8] = 0; - lsd2[8] = 0; + AnalogSignal analog_signal_array[12*(3+2)+12*(3+2)]; + int analog_signal_index; + + + analog_signal_index = 0; // we skip the status dibits that occur every 36 symbols // the first IMBE frame starts 14 symbols before next status - // so we start counter at 22 + // so we start counter at 36-14-1 = 21 status_count = 21; if (opts->errorbars == 1) @@ -55,63 +55,93 @@ processLDU1 (dsd_opts* opts, dsd_state* state) } // IMBE 1 +#ifdef TRACE_DSD + state->debug_prefix_2 = '0'; +#endif process_IMBE (opts, state, &status_count); // IMBE 2 +#ifdef TRACE_DSD + state->debug_prefix_2 = '1'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 2 - read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 9][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 8][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 9][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 8][0]), &status_count, analog_signal_array, &analog_signal_index); + analog_signal_array[0*5].sequence_broken = 1; // IMBE 3 +#ifdef TRACE_DSD + state->debug_prefix_2 = '2'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 3 - read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 5][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 4][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 5][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 4][0]), &status_count, analog_signal_array, &analog_signal_index); + analog_signal_array[4*5].sequence_broken = 1; // IMBE 4 +#ifdef TRACE_DSD + state->debug_prefix_2 = '3'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 4 - read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 1][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 0][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 1][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 0][0]), &status_count, analog_signal_array, &analog_signal_index); + analog_signal_array[8*5].sequence_broken = 1; // IMBE 5 +#ifdef TRACE_DSD + state->debug_prefix_2 = '4'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 5 - read_and_correct_hex_word (opts, state, &(hex_parity[11][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[10][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 9][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 8][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[11][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[10][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 9][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 8][0]), &status_count, analog_signal_array, &analog_signal_index); + analog_signal_array[12*5].sequence_broken = 1; // IMBE 6 +#ifdef TRACE_DSD + state->debug_prefix_2 = '5'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 6 - read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 5][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 4][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 5][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 4][0]), &status_count, analog_signal_array, &analog_signal_index); + analog_signal_array[16*5].sequence_broken = 1; // IMBE 7 +#ifdef TRACE_DSD + state->debug_prefix_2 = '6'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 7 - read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 1][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 0][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 1][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 0][0]), &status_count, analog_signal_array, &analog_signal_index); + analog_signal_array[20*5].sequence_broken = 1; // IMBE 8 +#ifdef TRACE_DSD + state->debug_prefix_2 = '7'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 8: LSD (low speed data) @@ -121,11 +151,11 @@ processLDU1 (dsd_opts* opts, dsd_state* state) for (i=0; i<=6; i+=2) { - read_dibit(opts, state, lsd+i, &status_count); + read_dibit(opts, state, lsd+i, &status_count, NULL, NULL); } for (i=0; i<=6; i+=2) { - read_dibit(opts, state, cyclic_parity+i, &status_count); + read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL); } for (i=0; i<8; i++) { @@ -134,11 +164,11 @@ processLDU1 (dsd_opts* opts, dsd_state* state) for (i=0; i<=6; i+=2) { - read_dibit(opts, state, lsd+i, &status_count); + read_dibit(opts, state, lsd+i, &status_count, NULL, NULL); } for (i=0; i<=6; i+=2) { - read_dibit(opts, state, cyclic_parity+i, &status_count); + read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL); } for (i=0; i<8; i++) { @@ -150,6 +180,9 @@ processLDU1 (dsd_opts* opts, dsd_state* state) } // IMBE 9 +#ifdef TRACE_DSD + state->debug_prefix_2 = '8'; +#endif process_IMBE (opts, state, &status_count); if (opts->errorbars == 1) @@ -165,18 +198,54 @@ processLDU1 (dsd_opts* opts, dsd_state* state) // trailing status symbol { int status; - status = getDibit (opts, state) + 48; + status = getDibit (opts, state) + '0'; // TODO: do something useful with the status bits... } // Error correct the hex_data using Reed-Solomon hex_parity - irrecoverable_errors = check_and_fix_redsolomon_24_12_13((char*)hex_data, (char*)hex_parity); - if (irrecoverable_errors == 1) { + irrecoverable_errors = check_and_fix_reedsolomon_24_12_13((char*)hex_data, (char*)hex_parity); + if (irrecoverable_errors == 1) + { state->debug_header_critical_errors++; - } + // We can correct (13-1)/2 = 6 errors. If we failed, it means that there were more than 6 errors in + // these 12+12 words. But take into account that each hex word was already error corrected with + // Hamming(10,6,3), which can correct 1 bits on each sequence of (6+4) bits. We could say that there + // were 7 errors of 2 bits. + update_error_stats(&state->p25_heuristics, 12*6+12*6, 7*2); + } + else + { + // Same comments as in processHDU. See there. + + char fixed_parity[12*6]; + + // Correct the dibits that we read according with hex_data values + correct_hamming_dibits((char*)hex_data, 12, analog_signal_array); + + // Generate again the Reed-Solomon parity + encode_reedsolomon_24_12_13((char*)hex_data, fixed_parity); + + // Correct the dibits that we read according with the fixed parity values + correct_hamming_dibits(fixed_parity, 12, analog_signal_array+12*(3+2)); + + // Once corrected, contribute this information to the heuristics module + contribute_to_heuristics(state->rf_mod, &(state->p25_heuristics), analog_signal_array, 12*(3+2)+12*(3+2)); + } + +#ifdef HEURISTICS_DEBUG + printf("(audio errors, header errors, critical header errors) (%i,%i,%i)\n", + state->debug_audio_errors, state->debug_header_errors, state->debug_header_critical_errors); +#endif + + // Now put the corrected data into the DSD structures + + lcformat[8] = 0; + mfid[8] = 0; + lcinfo[56] = 0; + lsd1[8] = 0; + lsd2[8] = 0; - // Put the corrected data into the DSD structures lcformat[0] = hex_data[11][0] + '0'; lcformat[1] = hex_data[11][1] + '0'; lcformat[2] = hex_data[11][2] + '0'; diff --git a/p25p1_ldu2.c b/p25p1_ldu2.c index 5b7fe15..238993f 100644 --- a/p25p1_ldu2.c +++ b/p25p1_ldu2.c @@ -20,6 +20,7 @@ #include "p25p1_ldu.h" #include "p25p1_check_ldu.h" +#include "p25p1_hdu.h" @@ -27,27 +28,26 @@ void processLDU2 (dsd_opts * opts, dsd_state * state) { // extracts IMBE frames from LDU frame - int i, j, k, dibit; + int i; char mi[73], algid[9], kid[17]; char lsd1[9], lsd2[9]; int algidhex, kidhex; int status_count; - char hex_data[16][6]; // Data in hex-words (6 bit words). A total of 12 hex words. - char hex_parity[8][6]; // Parity of the data, again in hex-word format. A total of 12 parity hex words. + char hex_data[16][6]; // Data in hex-words (6 bit words). A total of 16 hex words. + char hex_parity[8][6]; // Parity of the data, again in hex-word format. A total of 12 parity hex words. int irrecoverable_errors; - mi[72] = 0; - algid[8] = 0; - kid[16] = 0; - lsd1[8] = 0; - lsd2[8] = 0; + AnalogSignal analog_signal_array[16*(3+2)+8*(3+2)]; + int analog_signal_index; + + analog_signal_index = 0; // we skip the status dibits that occur every 36 symbols // the first IMBE frame starts 14 symbols before next status - // so we start counter at 22 + // so we start counter at 36-14-1 = 21 status_count = 21; if (opts->errorbars == 1) @@ -56,63 +56,93 @@ processLDU2 (dsd_opts * opts, dsd_state * state) } // IMBE 1 +#ifdef TRACE_DSD + state->debug_prefix_2 = '0'; +#endif process_IMBE (opts, state, &status_count); // IMBE 2 +#ifdef TRACE_DSD + state->debug_prefix_2 = '1'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 2 - read_and_correct_hex_word (opts, state, &(hex_data[15][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[14][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[13][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[12][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[15][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[14][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[13][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[12][0]), &status_count, analog_signal_array, &analog_signal_index); + analog_signal_array[0*5].sequence_broken = 1; // IMBE 3 +#ifdef TRACE_DSD + state->debug_prefix_2 = '2'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 3 - read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 9][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 8][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 9][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 8][0]), &status_count, analog_signal_array, &analog_signal_index); + analog_signal_array[4*5].sequence_broken = 1; // IMBE 4 +#ifdef TRACE_DSD + state->debug_prefix_2 = '3'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 4 - read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 5][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 4][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 5][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 4][0]), &status_count, analog_signal_array, &analog_signal_index); + analog_signal_array[8*5].sequence_broken = 1; // IMBE 5 +#ifdef TRACE_DSD + state->debug_prefix_2 = '4'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 5 - read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 1][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_data[ 0][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 1][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_data[ 0][0]), &status_count, analog_signal_array, &analog_signal_index); + analog_signal_array[12*5].sequence_broken = 1; // IMBE 6 +#ifdef TRACE_DSD + state->debug_prefix_2 = '5'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 6 - read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 5][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 4][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 5][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 4][0]), &status_count, analog_signal_array, &analog_signal_index); + analog_signal_array[16*5].sequence_broken = 1; // IMBE 7 +#ifdef TRACE_DSD + state->debug_prefix_2 = '6'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 7 - read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 1][0]), &status_count); - read_and_correct_hex_word (opts, state, &(hex_parity[ 0][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 1][0]), &status_count, analog_signal_array, &analog_signal_index); + read_and_correct_hex_word (opts, state, &(hex_parity[ 0][0]), &status_count, analog_signal_array, &analog_signal_index); + analog_signal_array[20*5].sequence_broken = 1; // IMBE 8 +#ifdef TRACE_DSD + state->debug_prefix_2 = '7'; +#endif process_IMBE (opts, state, &status_count); // Read data after IMBE 8: LSD (low speed data) @@ -122,11 +152,11 @@ processLDU2 (dsd_opts * opts, dsd_state * state) for (i=0; i<=6; i+=2) { - read_dibit(opts, state, lsd+i, &status_count); + read_dibit(opts, state, lsd+i, &status_count, NULL, NULL); } for (i=0; i<=6; i+=2) { - read_dibit(opts, state, cyclic_parity+i, &status_count); + read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL); } for (i=0; i<8; i++) { @@ -135,11 +165,11 @@ processLDU2 (dsd_opts * opts, dsd_state * state) for (i=0; i<=6; i+=2) { - read_dibit(opts, state, lsd+i, &status_count); + read_dibit(opts, state, lsd+i, &status_count, NULL, NULL); } for (i=0; i<=6; i+=2) { - read_dibit(opts, state, cyclic_parity+i, &status_count); + read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL); } for (i=0; i<8; i++) { @@ -151,6 +181,9 @@ processLDU2 (dsd_opts * opts, dsd_state * state) } // IMBE 9 +#ifdef TRACE_DSD + state->debug_prefix_2 = '8'; +#endif process_IMBE (opts, state, &status_count); if (opts->errorbars == 1) @@ -166,18 +199,55 @@ processLDU2 (dsd_opts * opts, dsd_state * state) // trailing status symbol { int status; - status = getDibit (opts, state) + 48; + status = getDibit (opts, state) + '0'; // TODO: do something useful with the status bits... } // Error correct the hex_data using Reed-Solomon hex_parity - irrecoverable_errors = check_and_fix_redsolomon_24_16_9((char*)hex_data, (char*)hex_parity); - if (irrecoverable_errors == 1) { + irrecoverable_errors = check_and_fix_reedsolomon_24_16_9((char*)hex_data, (char*)hex_parity); + if (irrecoverable_errors == 1) + { state->debug_header_critical_errors++; - } + + // We can correct (9-1)/2 = 4 errors. If we failed, it means that there were more than 4 errors in + // these 12+12 words. But take into account that each hex word was already error corrected with + // Hamming(10,6,3), which can correct 1 bits on each sequence of (6+4) bits. We could say that there + // were 5 errors of 2 bits. + update_error_stats(&state->p25_heuristics, 12*6+12*6, 5*2); + } + else + { + // Same comments as in processHDU. See there. + + char fixed_parity[8*6]; + + // Correct the dibits that we read according with hex_data values + correct_hamming_dibits((char*)hex_data, 16, analog_signal_array); + + // Generate again the Reed-Solomon parity + encode_reedsolomon_24_16_9((char*)hex_data, fixed_parity); + + // Correct the dibits that we read according with the fixed parity values + correct_hamming_dibits(fixed_parity, 8, analog_signal_array+16*(3+2)); + + // Once corrected, contribute this information to the heuristics module + contribute_to_heuristics(state->rf_mod, &(state->p25_heuristics), analog_signal_array, 16*(3+2)+8*(3+2)); + } - // Put the corrected data into the DSD structures +#ifdef HEURISTICS_DEBUG + printf("(audio errors, header errors, critical header errors) (%i,%i,%i)\n", + state->debug_audio_errors, state->debug_header_errors, state->debug_header_critical_errors); +#endif + + // Now put the corrected data into the DSD structures + + mi[72] = 0; + algid[8] = 0; + kid[16] = 0; + lsd1[8] = 0; + lsd2[8] = 0; + mi[ 0] = hex_data[15][0] + '0'; mi[ 1] = hex_data[15][1] + '0'; mi[ 2] = hex_data[15][2] + '0'; diff --git a/p25p1_tdu.c b/p25p1_tdu.c new file mode 100644 index 0000000..2401910 --- /dev/null +++ b/p25p1_tdu.c @@ -0,0 +1,34 @@ + + +#include "dsd.h" + +#include "p25p1_hdu.h" +#include "p25p1_heuristics.h" + + +void +processTDU (dsd_opts* opts, dsd_state* state) +{ + AnalogSignal analog_signal_array[14]; + int status_count; + + // we skip the status dibits that occur every 36 symbols + // the first IMBE frame starts 14 symbols before next status + // so we start counter at 36-14-1 = 21 + status_count = 21; + + // Next 14 dibits should be zeros + read_zeros(opts, state, analog_signal_array, 28, &status_count, 1); + + // Next we should find an status dibit + if (status_count != 35) { + printf("*** SYNC ERROR\n"); + } + + // trailing status symbol + { + int status; + status = getDibit (opts, state) + '0'; + // TODO: do something useful with the status bits... + } +} diff --git a/p25p1_tdulc.c b/p25p1_tdulc.c index 097970d..56ff081 100644 --- a/p25p1_tdulc.c +++ b/p25p1_tdulc.c @@ -17,141 +17,374 @@ #include "dsd.h" -void -processTDULC (dsd_opts * opts, dsd_state * state) -{ +#include "p25p1_hdu.h" +#include "p25p1_check_hdu.h" +#include "p25p1_check_ldu.h" +#include "p25p1_heuristics.h" - char lcinfo[57], lcformat[9], mfid[9]; +// Uncomment for some verbose debug info +//#define TDULC_DEBUG + +/** + * Reverse the order of bits in a 12-bit word. We need this to accommodate to the expected bit order in + * some algorithms. + * \param dodeca The 12-bit word to reverse. + */ +static void +swap_hex_words_bits(char* dodeca) +{ + int j; + for(j=0; j<6; j++) + { + int swap; + swap = dodeca[j]; + dodeca[j] = dodeca[j+6]; + dodeca[j+6] = swap; + } +} + +/** + * Reverse the order of bits in a sequence of six pairs of 12-bit words and their parities. + * \param dodeca_data Pointer to the start of the 12-bit words sequence. + * \param dodeca_parity Pointer to the parities sequence. + */ +static void +swap_hex_words(char* dodeca_data, char* dodeca_parity) +{ + int i; + for(i=0; i<6; i++) + { + swap_hex_words_bits(dodeca_data + i*12); + swap_hex_words_bits(dodeca_parity + i*12); + } +} + +/** + * Read an hex word, its parity bits and attempts to error correct it using the Hamming algorithm. + */ +static void +read_and_correct_dodeca_word (dsd_opts* opts, dsd_state* state, char* dodeca, int* status_count, + AnalogSignal* analog_signal_array, int* analog_signal_index) +{ + char parity[12]; + int fixed_errors; + int irrecoverable_errors; + + // Read the hex word + read_word (opts, state, dodeca, 12, status_count, analog_signal_array, analog_signal_index); + // Read the parity + read_golay24_parity (opts, state, parity, status_count, analog_signal_array, analog_signal_index); + +#ifdef TDULC_DEBUG + printf("["); + for (i = 0; i < 12; i++) + { + printf("%c", (dodeca[i] == 1)? 'X' : ' '); + } + printf("-"); + for (i = 0; i < 12; i++) + { + printf("%c", (parity[i] == 1)? 'X' : ' '); + } + printf("]"); +#endif + + // Use extended golay to error correct the dodeca word + irrecoverable_errors = check_and_fix_golay_24_12(dodeca, parity, &fixed_errors); + + state->debug_header_errors += fixed_errors; + if (irrecoverable_errors != 0) + { + state->debug_header_critical_errors++; + } + +#ifdef TDULC_DEBUG + printf(" -> ["); + for (i = 0; i < 12; i++) + { + printf("%c", (dodeca[i] == 1)? 'X' : ' '); + } + printf("]"); + if (irrecoverable_errors == 0) + { + if (fixed_errors > 0) + { + printf(" fixed!"); + } + } + else + { + printf(" IRRECOVERABLE"); + } + printf("\n"); +#endif +} + +/** + * Correct the information in analog_signal_array according with the content of data, which has been + * error corrected and should be valid. + * \param data A sequence of 12-bit words. + * \param count Number of words in the sequence. + * \param analog_signal_array Pointer to a sequence of AnalogSignal elements, as many as the value of count. + */ +static void +correct_golay_dibits_12(char* data, int count, AnalogSignal* analog_signal_array) +{ + int i, j; + int analog_signal_index; int dibit; + char parity[12]; + + + analog_signal_index = 0; + + for (i=count-1; i>=0; i--) + { + for (j=0; j<12; j+=2) // 6 iterations -> 6 dibits + { + dibit = (data[i*12+j] << 1) | data[i*12+j+1]; + analog_signal_array[analog_signal_index].corrected_dibit = dibit; + +#ifdef HEURISTICS_DEBUG + if (analog_signal_array[analog_signal_index].dibit != dibit) + { + printf("TDULC data word corrected from %i to %i, analog value %i\n", + analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value); + } +#endif + + analog_signal_index++; + } + + // Calculate the golay parity for the hex word + encode_golay_24_12(data+i*12, parity); + + for (j=0; j<12; j+=2) // 6 iterations -> 6 dibits + { + dibit = (parity[j] << 1) | parity[j+1]; + analog_signal_array[analog_signal_index].corrected_dibit = dibit; + +#ifdef HEURISTICS_DEBUG + if (analog_signal_array[analog_signal_index].dibit != dibit) + { + printf("TDULC parity corrected from %i to %i, analog value %i\n", + analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value); + } +#endif + + analog_signal_index++; + } + } +} + +void +read_zeros(dsd_opts* opts, dsd_state* state, AnalogSignal* analog_signal_array, unsigned int length, + int* status_count, int new_sequence) +{ + char* buffer; + unsigned int i; + int analog_signal_index; + + analog_signal_index = 0; + buffer = malloc(length); + read_dibit_update_analog_data (opts, state, buffer, length, status_count, analog_signal_array, &analog_signal_index); + free(buffer); + if (new_sequence) + { + analog_signal_array[0].sequence_broken = 1; + } + + for (i=0;irf_mod, &(state->p25_heuristics), analog_signal_array, length/2); +} + +void +processTDULC (dsd_opts* opts, dsd_state* state) +{ + int i; + char lcinfo[57], lcformat[9], mfid[9]; + + int status_count; + + char dodeca_data[6][12]; // Data in 12-bit words. A total of 6 words. + char dodeca_parity[6][12]; // Reed-Solomon parity of the data. A total of 6 parity 12-bit words. + + int irrecoverable_errors; + + AnalogSignal analog_signal_array[6*(6+6)+6*(6+6)+10]; + int analog_signal_index; + + + analog_signal_index = 0; + + // we skip the status dibits that occur every 36 symbols + // the first IMBE frame starts 14 symbols before next status + // so we start counter at 36-14-1 = 21 + status_count = 21; + + for(i=5; i>=0; i--) { + read_and_correct_dodeca_word (opts, state, &(dodeca_data[i][0]), &status_count, analog_signal_array, &analog_signal_index); + } + + for(i=5; i>=0; i--) { + read_and_correct_dodeca_word (opts, state, &(dodeca_parity[i][0]), &status_count, analog_signal_array, &analog_signal_index); + } + + // Swap the two 6-bit words to accommodate for the expected word order of the Reed-Solomon decoding + swap_hex_words((char*)dodeca_data, (char*)dodeca_parity); + + // Error correct the hex_data using Reed-Solomon hex_parity + irrecoverable_errors = check_and_fix_reedsolomon_24_12_13((char*)dodeca_data, (char*)dodeca_parity); + + // Recover the original order + swap_hex_words((char*)dodeca_data, (char*)dodeca_parity); + + if (irrecoverable_errors == 1) + { + state->debug_header_critical_errors++; + + // We can correct (13-1)/2 = 6 errors. If we failed, it means that there were more than 6 errors in + // these 12+12 words. But take into account that each hex word was already error corrected with + // Golay 24, which can correct 3 bits on each sequence of (12+12) bits. We could say that there were + // 7 errors of 4 bits. + update_error_stats(&state->p25_heuristics, 12*6+12*6, 7*4); + + } + else + { + // Same comments as in processHDU. See there. + + char fixed_parity[6*12]; + + // Correct the dibits that we read according with hex_data values + correct_golay_dibits_12((char*)dodeca_data, 6, analog_signal_array); + + // Generate again the Reed-Solomon parity + // Now, swap again for Reed-Solomon + swap_hex_words((char*)dodeca_data, (char*)dodeca_parity); + encode_reedsolomon_24_12_13((char*)dodeca_data, fixed_parity); + // Swap again to recover the original order + swap_hex_words((char*)dodeca_data, fixed_parity); + + // Correct the dibits that we read according with the fixed parity values + correct_golay_dibits_12(fixed_parity, 6, analog_signal_array+6*(6+6)); + + // Once corrected, contribute this information to the heuristics module + analog_signal_array[0].sequence_broken = 1; + contribute_to_heuristics(state->rf_mod, &(state->p25_heuristics), analog_signal_array, 6*(6+6)+6*(6+6)); + } + + + // Next 10 dibits should be zeros + read_zeros(opts, state, analog_signal_array + 6*(6+6)+6*(6+6), 20, &status_count, 0); + + // Next we should find an status dibit + if (status_count != 35) { + printf("*** SYNC ERROR\n"); + } + + // trailing status symbol + { + int status; + status = getDibit (opts, state) + '0'; + // TODO: do something useful with the status bits... + } + + // Put the corrected data into the DSD structures lcformat[8] = 0; mfid[8] = 0; lcinfo[56] = 0; - // Now processing NID + lcformat[0] = dodeca_data[5][ 0] + '0'; + lcformat[1] = dodeca_data[5][ 1] + '0'; + lcformat[2] = dodeca_data[5][ 2] + '0'; + lcformat[3] = dodeca_data[5][ 3] + '0'; + lcformat[4] = dodeca_data[5][ 4] + '0'; + lcformat[5] = dodeca_data[5][ 5] + '0'; + lcformat[6] = dodeca_data[5][ 6] + '0'; + lcformat[7] = dodeca_data[5][ 7] + '0'; + mfid[0] = dodeca_data[5][ 8] + '0'; + mfid[1] = dodeca_data[5][ 9] + '0'; + mfid[2] = dodeca_data[5][10] + '0'; + mfid[3] = dodeca_data[5][11] + '0'; - dibit = getDibit (opts, state); - lcformat[0] = (1 & (dibit >> 1)) + 48; // bit 1 - lcformat[1] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcformat[2] = (1 & (dibit >> 1)) + 48; // bit 1 - lcformat[3] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcformat[4] = (1 & (dibit >> 1)) + 48; // bit 1 - lcformat[5] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcformat[6] = (1 & (dibit >> 1)) + 48; // bit 1 - lcformat[7] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mfid[0] = (1 & (dibit >> 1)) + 48; // bit 1 - mfid[1] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mfid[2] = (1 & (dibit >> 1)) + 48; // bit 1 - mfid[3] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 6); + mfid[4] = dodeca_data[4][ 0] + '0'; + mfid[5] = dodeca_data[4][ 1] + '0'; + mfid[6] = dodeca_data[4][ 2] + '0'; + mfid[7] = dodeca_data[4][ 3] + '0'; + lcinfo[0] = dodeca_data[4][ 4] + '0'; + lcinfo[1] = dodeca_data[4][ 5] + '0'; + lcinfo[2] = dodeca_data[4][ 6] + '0'; + lcinfo[3] = dodeca_data[4][ 7] + '0'; + lcinfo[4] = dodeca_data[4][ 8] + '0'; + lcinfo[5] = dodeca_data[4][ 9] + '0'; + lcinfo[6] = dodeca_data[4][10] + '0'; + lcinfo[7] = dodeca_data[4][11] + '0'; - dibit = getDibit (opts, state); - mfid[4] = (1 & (dibit >> 1)) + 48; // bit 1 - mfid[5] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mfid[6] = (1 & (dibit >> 1)) + 48; // bit 1 - mfid[7] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 1); - dibit = getDibit (opts, state); - lcinfo[0] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[1] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[2] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[3] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[4] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[5] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[6] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[7] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 6); + lcinfo[8] = dodeca_data[3][ 0] + '0'; + lcinfo[9] = dodeca_data[3][ 1] + '0'; + lcinfo[10] = dodeca_data[3][ 2] + '0'; + lcinfo[11] = dodeca_data[3][ 3] + '0'; + lcinfo[12] = dodeca_data[3][ 4] + '0'; + lcinfo[13] = dodeca_data[3][ 5] + '0'; + lcinfo[14] = dodeca_data[3][ 6] + '0'; + lcinfo[15] = dodeca_data[3][ 7] + '0'; + lcinfo[16] = dodeca_data[3][ 8] + '0'; + lcinfo[17] = dodeca_data[3][ 9] + '0'; + lcinfo[18] = dodeca_data[3][10] + '0'; + lcinfo[19] = dodeca_data[3][11] + '0'; - dibit = getDibit (opts, state); - lcinfo[8] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[9] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[10] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[11] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[12] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[13] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[14] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[15] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[16] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[17] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[18] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[19] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 6); + lcinfo[20] = dodeca_data[2][ 0] + '0'; + lcinfo[21] = dodeca_data[2][ 1] + '0'; + lcinfo[22] = dodeca_data[2][ 2] + '0'; + lcinfo[23] = dodeca_data[2][ 3] + '0'; + lcinfo[24] = dodeca_data[2][ 4] + '0'; + lcinfo[25] = dodeca_data[2][ 5] + '0'; + lcinfo[26] = dodeca_data[2][ 6] + '0'; + lcinfo[27] = dodeca_data[2][ 7] + '0'; + lcinfo[28] = dodeca_data[2][ 8] + '0'; + lcinfo[29] = dodeca_data[2][ 9] + '0'; + lcinfo[30] = dodeca_data[2][10] + '0'; + lcinfo[31] = dodeca_data[2][11] + '0'; - dibit = getDibit (opts, state); - lcinfo[20] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[21] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[22] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[23] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[24] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[25] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[26] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[27] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[28] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[29] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[30] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[31] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 6); + lcinfo[32] = dodeca_data[1][ 0] + '0'; + lcinfo[33] = dodeca_data[1][ 1] + '0'; + lcinfo[34] = dodeca_data[1][ 2] + '0'; + lcinfo[35] = dodeca_data[1][ 3] + '0'; + lcinfo[36] = dodeca_data[1][ 4] + '0'; + lcinfo[37] = dodeca_data[1][ 5] + '0'; + lcinfo[38] = dodeca_data[1][ 6] + '0'; + lcinfo[39] = dodeca_data[1][ 7] + '0'; + lcinfo[40] = dodeca_data[1][ 8] + '0'; + lcinfo[41] = dodeca_data[1][ 9] + '0'; + lcinfo[42] = dodeca_data[1][10] + '0'; + lcinfo[43] = dodeca_data[1][11] + '0'; - dibit = getDibit (opts, state); - lcinfo[32] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[33] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 1); - dibit = getDibit (opts, state); - lcinfo[34] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[35] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[36] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[37] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[38] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[39] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[40] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[41] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[42] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[43] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 6); - - dibit = getDibit (opts, state); - lcinfo[44] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[45] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[46] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[47] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[48] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[49] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[50] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[51] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[52] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[53] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[54] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[55] = (1 & dibit) + 48; // bit 0 - - skipDibit (opts, state, 91); + lcinfo[44] = dodeca_data[0][ 0] + '0'; + lcinfo[45] = dodeca_data[0][ 1] + '0'; + lcinfo[46] = dodeca_data[0][ 2] + '0'; + lcinfo[47] = dodeca_data[0][ 3] + '0'; + lcinfo[48] = dodeca_data[0][ 4] + '0'; + lcinfo[49] = dodeca_data[0][ 5] + '0'; + lcinfo[50] = dodeca_data[0][ 6] + '0'; + lcinfo[51] = dodeca_data[0][ 7] + '0'; + lcinfo[52] = dodeca_data[0][ 8] + '0'; + lcinfo[53] = dodeca_data[0][ 9] + '0'; + lcinfo[54] = dodeca_data[0][10] + '0'; + lcinfo[55] = dodeca_data[0][11] + '0'; processP25lcw (opts, state, lcformat, mfid, lcinfo); } diff --git a/test/golay24-test.cpp b/test/golay24-test.cpp index 14950de..dbae866 100644 --- a/test/golay24-test.cpp +++ b/test/golay24-test.cpp @@ -40,12 +40,12 @@ protected: { DSDGolay24 golay24; - unsigned int trashed_codeword = golay24.adapt_to_codeword(hex, sgp); + unsigned int trashed_codeword = golay24.adapt_to_codeword(hex, 6, sgp); //printf("[%s]", hex_to_bin24(trashed_codeword)); int fixed_errors = 0; - int many_errors = golay24.decode(hex, sgp, &fixed_errors); // try to correct bit errors + int many_errors = golay24.decode_6(hex, sgp, &fixed_errors); // try to correct bit errors /* printf(" -> "); @@ -72,6 +72,18 @@ protected: //printf("\n"); } + + static void check_encode(char* hex, char* expected_parity) + { + DSDGolay24 golay24; + char parity[12]; + + golay24.encode_6(hex, parity); + + for(unsigned int i=0; i<12; i++) { + EXPECT_EQ(expected_parity[i], parity[i]); + } + } }; TEST_F(Golay24Test, Test1) @@ -136,3 +148,27 @@ TEST_F(Golay24Test, Test7) fix_golay24(hex, parity, expected, 2); } + +TEST_F(Golay24Test, Test_encode_1) +{ + char hex[6] = { 1, 0, 1, 0, 1, 0}; + char expected_parity[12] = { 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1}; + + check_encode(hex, expected_parity); +} + +TEST_F(Golay24Test, Test_encode_2) +{ + char hex[6] = { 0, 0, 1, 0, 0, 0}; + char expected_parity[12] = { 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0}; + + check_encode(hex, expected_parity); +} + +TEST_F(Golay24Test, Test_encode_3) +{ + char hex[6] = { 0, 0, 0, 0, 0, 0}; + char expected_parity[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + check_encode(hex, expected_parity); +} diff --git a/test/hamming-test.cpp b/test/hamming-test.cpp index c842c76..36f2a0f 100644 --- a/test/hamming-test.cpp +++ b/test/hamming-test.cpp @@ -30,7 +30,7 @@ protected: std::cout << std::endl; } - static void check_hamming(int v, int expected_v, int expected_errors) + static void check_decode(int v, int expected_v, int expected_errors) { Hamming_10_6_3 hamming; Hamming_10_6_3_TableImpl hamming_table; @@ -43,17 +43,17 @@ protected: //print_debug(v, output_1, error_count_1); if (expected_errors != -1) { - EXPECT_THAT(expected_errors, error_count_1); + EXPECT_EQ(expected_errors, error_count_1); } - EXPECT_THAT(error_count_1, error_count_2); + EXPECT_EQ(error_count_1, error_count_2); if (expected_v != -1) { - EXPECT_THAT(expected_v, output_1); + EXPECT_EQ(expected_v, output_1); } - EXPECT_THAT(output_1, output_2); + EXPECT_EQ(output_1, output_2); } - static void check_hamming(Hamming_Inteface* hamming, char* hex, char* parity, int expected_errors, char* expected) + static void check_decode(Hamming_Inteface* hamming, char* hex, char* parity, int expected_errors, char* expected) { int value = Hamming_10_6_3_TableImpl::convert_hex_parity_to_int(hex, parity); int error_count = hamming->decode(hex, parity); @@ -61,12 +61,34 @@ protected: //print_debug(value, fixed, error_count); - EXPECT_THAT(expected_errors, error_count); + EXPECT_EQ(expected_errors, error_count); for (unsigned int i=0; i<6; i++) { - EXPECT_THAT(expected[i], hex[i]); + EXPECT_EQ(expected[i], hex[i]); } } + static void check_encode(Hamming_Inteface* hamming, int input) + { + int parity = hamming->encode(input); + + // Check it + EXPECT_LT(parity, 16); + int v = (input << 4) | parity; + int output; + int error_count = hamming->decode(v, &output); + EXPECT_EQ(error_count, 0); + EXPECT_EQ(output, input); + } + + static void check_encode(Hamming_Inteface* hamming, char* hex) + { + char parity[4]; + hamming->encode(hex, parity); + + // Check it + int error_count = hamming->decode(hex, parity); + EXPECT_EQ(error_count, 0); + } }; TEST_F(HammingTest, Test1) @@ -74,7 +96,7 @@ TEST_F(HammingTest, Test1) // OK std::bitset<10> value(std::string("1010100110")); std::bitset< 6> expected(std::string("101010")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 0); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 0); } TEST_F(HammingTest, Test2) @@ -82,7 +104,7 @@ TEST_F(HammingTest, Test2) // Error on parity bit 0 (9 is the left-most and 0 is the right-most) std::bitset<10> value(std::string("1010100111")); std::bitset< 6> expected(std::string("101010")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1); } TEST_F(HammingTest, Test3) @@ -90,7 +112,7 @@ TEST_F(HammingTest, Test3) // Error on parity bit 1 (9 is the left-most and 0 is the right-most) std::bitset<10> value(std::string("1010100100")); std::bitset< 6> expected(std::string("101010")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1); } TEST_F(HammingTest, Test4) @@ -98,7 +120,7 @@ TEST_F(HammingTest, Test4) // Error on parity bit 2 (9 is the left-most and 0 is the right-most) std::bitset<10> value(std::string("1010100010")); std::bitset< 6> expected(std::string("101010")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1); } TEST_F(HammingTest, Test5) @@ -106,7 +128,7 @@ TEST_F(HammingTest, Test5) // Error on parity bit 3 (9 is the left-most and 0 is the right-most) std::bitset<10> value(std::string("1010101110")); std::bitset< 6> expected(std::string("101010")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1); } TEST_F(HammingTest, Test6) @@ -114,7 +136,7 @@ TEST_F(HammingTest, Test6) // Error on bit 4 (9 is the left-most and 0 is the right-most) std::bitset<10> value(std::string("1010110110")); std::bitset< 6> expected(std::string("101010")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1); } TEST_F(HammingTest, Test7) @@ -122,7 +144,7 @@ TEST_F(HammingTest, Test7) // Error on bit 5 (9 is the left-most and 0 is the right-most) std::bitset<10> value(std::string("1010000110")); std::bitset< 6> expected(std::string("101010")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1); } TEST_F(HammingTest, Test8) @@ -130,7 +152,7 @@ TEST_F(HammingTest, Test8) // Error on bit 6 (9 is the left-most and 0 is the right-most) std::bitset<10> value(std::string("1011100110")); std::bitset< 6> expected(std::string("101010")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1); } TEST_F(HammingTest, Test9) @@ -138,7 +160,7 @@ TEST_F(HammingTest, Test9) // Error on bit 7 (9 is the left-most and 0 is the right-most) std::bitset<10> value(std::string("1000100110")); std::bitset< 6> expected(std::string("101010")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1); } TEST_F(HammingTest, Test10) @@ -146,7 +168,7 @@ TEST_F(HammingTest, Test10) // Error on bit 8 (9 is the left-most and 0 is the right-most) std::bitset<10> value(std::string("1110100110")); std::bitset< 6> expected(std::string("101010")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1); } TEST_F(HammingTest, Test11) @@ -154,7 +176,7 @@ TEST_F(HammingTest, Test11) // Error on bit 9 (9 is the left-most and 0 is the right-most) std::bitset<10> value(std::string("0010100110")); std::bitset< 6> expected(std::string("101010")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1); } TEST_F(HammingTest, Test12) @@ -162,7 +184,7 @@ TEST_F(HammingTest, Test12) // Two errors std::bitset<10> value(std::string("0010100111")); std::bitset< 6> expected(std::string("001010")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 2); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 2); } TEST_F(HammingTest, Test13) @@ -170,7 +192,7 @@ TEST_F(HammingTest, Test13) // Two errors, in this case they go undetected, thinks it's a parity error std::bitset<10> value(std::string("1011000110")); std::bitset< 6> expected(std::string("101100")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1); } TEST_F(HammingTest, Test14) @@ -178,14 +200,14 @@ TEST_F(HammingTest, Test14) // OK std::bitset<10> value(std::string("0001000111")); std::bitset< 6> expected(std::string("000100")); - check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 0); + check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 0); } TEST_F(HammingTest, TestEveryValue) { // Test every posible value for (int v=0; v<1023; v++) { - check_hamming(v, -1, -1); + check_decode(v, -1, -1); } } @@ -196,10 +218,10 @@ TEST_F(HammingTest, Test_hex_parity_interface_no_errors) char parity[4] = {1,0,1,1}; Hamming_10_6_3 hamming; - check_hamming(&hamming, hex, parity, 0, fixed); + check_decode(&hamming, hex, parity, 0, fixed); Hamming_10_6_3_TableImpl hamming_table; - check_hamming(&hamming_table, hex, parity, 0, fixed); + check_decode(&hamming_table, hex, parity, 0, fixed); } TEST_F(HammingTest, Test_hex_parity_interface_one_error_1) @@ -210,11 +232,11 @@ TEST_F(HammingTest, Test_hex_parity_interface_one_error_1) char parity[4] = {1,0,1,1}; Hamming_10_6_3 hamming; - check_hamming(&hamming, hex_1, parity, 1, fixed); + check_decode(&hamming, hex_1, parity, 1, fixed); // hex is modified in place Hamming_10_6_3_TableImpl hamming_table; - check_hamming(&hamming_table, hex_2, parity, 1, fixed); + check_decode(&hamming_table, hex_2, parity, 1, fixed); // hex is modified in place } @@ -226,11 +248,11 @@ TEST_F(HammingTest, Test_hex_parity_interface_one_error_2) char parity[4] = {0,0,0,0}; Hamming_10_6_3 hamming; - check_hamming(&hamming, hex_1, parity, 1, fixed); + check_decode(&hamming, hex_1, parity, 1, fixed); // hex is modified in place Hamming_10_6_3_TableImpl hamming_table; - check_hamming(&hamming_table, hex_2, parity, 1, fixed); + check_decode(&hamming_table, hex_2, parity, 1, fixed); // hex is modified in place } @@ -242,10 +264,41 @@ TEST_F(HammingTest, Test_hex_parity_interface_one_error_3) char parity[4] = {0,0,0,0}; Hamming_10_6_3 hamming; - check_hamming(&hamming, hex_1, parity, 1, fixed); + check_decode(&hamming, hex_1, parity, 1, fixed); // hex is modified in place Hamming_10_6_3_TableImpl hamming_table; - check_hamming(&hamming_table, hex_2, parity, 1, fixed); + check_decode(&hamming_table, hex_2, parity, 1, fixed); // hex is modified in place } + +TEST_F(HammingTest, Test_encoding_1) +{ + Hamming_10_6_3 hamming; + Hamming_10_6_3_TableImpl hamming_table; + + for (int i=0; i<64; i++) { + check_encode(&hamming, i); + check_encode(&hamming_table, i); + } +} + +TEST_F(HammingTest, Test_encoding_char) +{ + Hamming_10_6_3 hamming; + Hamming_10_6_3_TableImpl hamming_table; + + char hex[6]; + + for (int i=0; i<64; i++) { + + // Convert i to char array + int input = i; + for (int j=5; j>=0; j--) { + hex[j] = input & 1; + input >>= 1; + } + check_encode(&hamming, hex); + check_encode(&hamming_table, hex); + } +} diff --git a/test/reedsolomon-test.cpp b/test/reedsolomon-test.cpp index 3bf6786..ad5b9d6 100644 --- a/test/reedsolomon-test.cpp +++ b/test/reedsolomon-test.cpp @@ -7,19 +7,9 @@ #include "ReedSolomon.hpp" -static void byte_to_binary(char* b, int x) -{ - int z, i; - - for (z = 32, i=0; z > 0; z >>= 1, i++) { - b[i] = ((x & z) != 0) ? 'X' : ' '; - } - b[6] = 0; -} - TEST(ReedSolomonTest, Test1) { - ReedSolomon_63_47_17 rs; + ReedSolomon_63<8> rs; int recd[63] = {}; int expected[63] = {}; int output[63]; @@ -90,3 +80,68 @@ TEST(ReedSolomonTest, Test1) EXPECT_THAT(expected, testing::ElementsAreArray(output, 63)); } + +static void generate_random_bits(char* p, unsigned int count) +{ + for (unsigned int i=0; i RAND_MAX/2)? 1 : 0; + } +} + +TEST(ReedSolomonTest, Test_encode_24_12_13) +{ + char hex[12*6]; + char parity[12*6]; + + DSDReedSolomon_24_12_13 rs; + + for (unsigned i=0; i<1000; i++) { + generate_random_bits((char*)hex, 12*6); + + // Make a copy + char expected[12*6]; + + memcpy(expected, hex, 12*6); + + + + // Encode + rs.encode(hex, parity); + + // Decode back, should have the same result and no errors + int irrecoverable_errors = rs.decode(hex, parity); + + EXPECT_EQ(0, irrecoverable_errors); + + EXPECT_THAT(expected, testing::ElementsAreArray(hex, 12*6)); + } +} + +TEST(ReedSolomonTest, Test_encode_24_16_9) +{ + char hex[16*6]; + char parity[8*6]; + + DSDReedSolomon_24_16_9 rs; + + for (unsigned i=0; i<1000; i++) { + generate_random_bits((char*)hex, 16*6); + + // Make a copy + char expected[16*6]; + + memcpy(expected, hex, 16*6); + + + + // Encode + rs.encode(hex, parity); + + // Decode back, should have the same result and no errors + int irrecoverable_errors = rs.decode(hex, parity); + + EXPECT_EQ(0, irrecoverable_errors); + + EXPECT_THAT(expected, testing::ElementsAreArray(hex, 16*6)); + } +} From 6ab62d006a6d19c1360e1d0a99feb12f01dacdfe Mon Sep 17 00:00:00 2001 From: Jared Szechy Date: Sat, 1 Mar 2014 18:13:47 -0500 Subject: [PATCH 03/10] Add itpp as a requirement in readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ce11a54..4469bf2 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ impact performance. * cmake * mbelib * sndfile +* itpp (IT++) >= v4.3 ### Example building instructions on Ubuntu: From 1e854adb845278276da70f15332761629906957b Mon Sep 17 00:00:00 2001 From: Jared Szechy Date: Tue, 11 Mar 2014 22:29:15 -0400 Subject: [PATCH 04/10] Use gtest for golay24 and reed-solomon tests --- .gitignore | 1 + CMakeLists.txt | 6 + test/CMakeLists.txt | 20 + test/gmock/CMakeLists.txt | 45 + test/gmock/include/gmock/gmock-actions.h | 1078 ++++ .../gmock/include/gmock/gmock-cardinalities.h | 147 + .../include/gmock/gmock-generated-actions.h | 2415 ++++++++ .../gmock/gmock-generated-actions.h.pump | 821 +++ .../gmock/gmock-generated-function-mockers.h | 991 ++++ .../gmock-generated-function-mockers.h.pump | 265 + .../include/gmock/gmock-generated-matchers.h | 2190 +++++++ .../gmock/gmock-generated-matchers.h.pump | 674 +++ .../gmock/gmock-generated-nice-strict.h | 397 ++ .../gmock/gmock-generated-nice-strict.h.pump | 161 + test/gmock/include/gmock/gmock-matchers.h | 3986 +++++++++++++ test/gmock/include/gmock/gmock-more-actions.h | 233 + .../gmock/include/gmock/gmock-more-matchers.h | 58 + .../gmock/include/gmock/gmock-spec-builders.h | 1791 ++++++ test/gmock/include/gmock/gmock.h | 94 + .../internal/gmock-generated-internal-utils.h | 279 + .../gmock-generated-internal-utils.h.pump | 136 + .../gmock/internal/gmock-internal-utils.h | 498 ++ .../gmock/include/gmock/internal/gmock-port.h | 78 + test/gmock/src/gmock-all.cc | 47 + test/gmock/src/gmock-cardinalities.cc | 156 + test/gmock/src/gmock-internal-utils.cc | 174 + test/gmock/src/gmock-matchers.cc | 498 ++ test/gmock/src/gmock-spec-builders.cc | 813 +++ test/gmock/src/gmock.cc | 182 + test/gmock/src/gmock_main.cc | 54 + test/golay24-test.cpp | 133 + test/gtest/CMakeLists.txt | 69 + test/gtest/cmake/internal_utils.cmake | 227 + test/gtest/include/gtest/gtest-death-test.h | 294 + test/gtest/include/gtest/gtest-message.h | 250 + test/gtest/include/gtest/gtest-param-test.h | 1421 +++++ .../include/gtest/gtest-param-test.h.pump | 487 ++ test/gtest/include/gtest/gtest-printers.h | 855 +++ test/gtest/include/gtest/gtest-spi.h | 232 + test/gtest/include/gtest/gtest-test-part.h | 179 + test/gtest/include/gtest/gtest-typed-test.h | 259 + test/gtest/include/gtest/gtest.h | 2291 ++++++++ test/gtest/include/gtest/gtest_pred_impl.h | 358 ++ test/gtest/include/gtest/gtest_prod.h | 58 + .../internal/gtest-death-test-internal.h | 319 + .../include/gtest/internal/gtest-filepath.h | 206 + .../include/gtest/internal/gtest-internal.h | 1158 ++++ .../include/gtest/internal/gtest-linked_ptr.h | 233 + .../internal/gtest-param-util-generated.h | 5143 +++++++++++++++++ .../gtest-param-util-generated.h.pump | 301 + .../include/gtest/internal/gtest-param-util.h | 619 ++ .../gtest/include/gtest/internal/gtest-port.h | 1947 +++++++ .../include/gtest/internal/gtest-string.h | 167 + .../include/gtest/internal/gtest-tuple.h | 1012 ++++ .../include/gtest/internal/gtest-tuple.h.pump | 339 ++ .../include/gtest/internal/gtest-type-util.h | 3331 +++++++++++ .../gtest/internal/gtest-type-util.h.pump | 297 + test/gtest/src/gtest-all.cc | 48 + test/gtest/src/gtest-death-test.cc | 1344 +++++ test/gtest/src/gtest-filepath.cc | 382 ++ test/gtest/src/gtest-internal-inl.h | 1218 ++++ test/gtest/src/gtest-port.cc | 805 +++ test/gtest/src/gtest-printers.cc | 363 ++ test/gtest/src/gtest-test-part.cc | 110 + test/gtest/src/gtest-typed-test.cc | 110 + test/gtest/src/gtest.cc | 5015 ++++++++++++++++ test/gtest/src/gtest_main.cc | 38 + test/reedsolomon-test.cpp | 57 + test/test.cpp | 7 + test_Golay24.cpp | 142 - test_ReedSolomon.cpp | 138 - 71 files changed, 49970 insertions(+), 280 deletions(-) create mode 100644 test/CMakeLists.txt create mode 100644 test/gmock/CMakeLists.txt create mode 100644 test/gmock/include/gmock/gmock-actions.h create mode 100644 test/gmock/include/gmock/gmock-cardinalities.h create mode 100644 test/gmock/include/gmock/gmock-generated-actions.h create mode 100644 test/gmock/include/gmock/gmock-generated-actions.h.pump create mode 100644 test/gmock/include/gmock/gmock-generated-function-mockers.h create mode 100644 test/gmock/include/gmock/gmock-generated-function-mockers.h.pump create mode 100644 test/gmock/include/gmock/gmock-generated-matchers.h create mode 100644 test/gmock/include/gmock/gmock-generated-matchers.h.pump create mode 100644 test/gmock/include/gmock/gmock-generated-nice-strict.h create mode 100644 test/gmock/include/gmock/gmock-generated-nice-strict.h.pump create mode 100644 test/gmock/include/gmock/gmock-matchers.h create mode 100644 test/gmock/include/gmock/gmock-more-actions.h create mode 100644 test/gmock/include/gmock/gmock-more-matchers.h create mode 100644 test/gmock/include/gmock/gmock-spec-builders.h create mode 100644 test/gmock/include/gmock/gmock.h create mode 100644 test/gmock/include/gmock/internal/gmock-generated-internal-utils.h create mode 100644 test/gmock/include/gmock/internal/gmock-generated-internal-utils.h.pump create mode 100644 test/gmock/include/gmock/internal/gmock-internal-utils.h create mode 100644 test/gmock/include/gmock/internal/gmock-port.h create mode 100644 test/gmock/src/gmock-all.cc create mode 100644 test/gmock/src/gmock-cardinalities.cc create mode 100644 test/gmock/src/gmock-internal-utils.cc create mode 100644 test/gmock/src/gmock-matchers.cc create mode 100644 test/gmock/src/gmock-spec-builders.cc create mode 100644 test/gmock/src/gmock.cc create mode 100644 test/gmock/src/gmock_main.cc create mode 100644 test/golay24-test.cpp create mode 100644 test/gtest/CMakeLists.txt create mode 100644 test/gtest/cmake/internal_utils.cmake create mode 100644 test/gtest/include/gtest/gtest-death-test.h create mode 100644 test/gtest/include/gtest/gtest-message.h create mode 100644 test/gtest/include/gtest/gtest-param-test.h create mode 100644 test/gtest/include/gtest/gtest-param-test.h.pump create mode 100644 test/gtest/include/gtest/gtest-printers.h create mode 100644 test/gtest/include/gtest/gtest-spi.h create mode 100644 test/gtest/include/gtest/gtest-test-part.h create mode 100644 test/gtest/include/gtest/gtest-typed-test.h create mode 100644 test/gtest/include/gtest/gtest.h create mode 100644 test/gtest/include/gtest/gtest_pred_impl.h create mode 100644 test/gtest/include/gtest/gtest_prod.h create mode 100644 test/gtest/include/gtest/internal/gtest-death-test-internal.h create mode 100644 test/gtest/include/gtest/internal/gtest-filepath.h create mode 100644 test/gtest/include/gtest/internal/gtest-internal.h create mode 100644 test/gtest/include/gtest/internal/gtest-linked_ptr.h create mode 100644 test/gtest/include/gtest/internal/gtest-param-util-generated.h create mode 100644 test/gtest/include/gtest/internal/gtest-param-util-generated.h.pump create mode 100644 test/gtest/include/gtest/internal/gtest-param-util.h create mode 100644 test/gtest/include/gtest/internal/gtest-port.h create mode 100644 test/gtest/include/gtest/internal/gtest-string.h create mode 100644 test/gtest/include/gtest/internal/gtest-tuple.h create mode 100644 test/gtest/include/gtest/internal/gtest-tuple.h.pump create mode 100644 test/gtest/include/gtest/internal/gtest-type-util.h create mode 100644 test/gtest/include/gtest/internal/gtest-type-util.h.pump create mode 100644 test/gtest/src/gtest-all.cc create mode 100644 test/gtest/src/gtest-death-test.cc create mode 100644 test/gtest/src/gtest-filepath.cc create mode 100644 test/gtest/src/gtest-internal-inl.h create mode 100644 test/gtest/src/gtest-port.cc create mode 100644 test/gtest/src/gtest-printers.cc create mode 100644 test/gtest/src/gtest-test-part.cc create mode 100644 test/gtest/src/gtest-typed-test.cc create mode 100644 test/gtest/src/gtest.cc create mode 100644 test/gtest/src/gtest_main.cc create mode 100644 test/reedsolomon-test.cpp create mode 100644 test/test.cpp delete mode 100644 test_Golay24.cpp delete mode 100644 test_ReedSolomon.cpp diff --git a/.gitignore b/.gitignore index 9d4ef4e..b2954aa 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ dsd *.so* *.dylib build +.DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt index e85f58f..300ee00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,3 +37,9 @@ configure_file( add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + +option(DISABLE_TEST "Disable building of test framework." OFF) + +if (NOT DISABLE_TEST) + add_subdirectory(test) +endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..5073575 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,20 @@ +project(dsdtest) + +add_subdirectory(gtest) +add_subdirectory(gmock) + +FILE(GLOB SRCS *.cpp) + +include_directories( + ${PROJECT_SOURCE_DIR}/gtest/include + ${PROJECT_SOURCE_DIR}/gmock/include + ${dsd_SOURCE_DIR} +) + +add_custom_target(test + DEPENDS dsdtest + COMMAND dsdtest +) + +ADD_EXECUTABLE(dsdtest ${SRCS}) +TARGET_LINK_LIBRARIES(dsdtest gmock gtest) diff --git a/test/gmock/CMakeLists.txt b/test/gmock/CMakeLists.txt new file mode 100644 index 0000000..ae4dfc6 --- /dev/null +++ b/test/gmock/CMakeLists.txt @@ -0,0 +1,45 @@ +######################################################################## +# CMake build script for Google Mock. +# +# To run the tests for Google Mock itself on Linux, use 'make test' or +# ctest. You can select which tests to run using 'ctest -R regex'. +# For more options, run 'ctest --help'. + +# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to +# make it prominent in the GUI. +option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) + +######################################################################## +# +# Project-wide settings + +# Name of the project. +# +# CMake files in this project can refer to the root source directory +# as ${gmock_SOURCE_DIR} and to the root binary directory as +# ${gmock_BINARY_DIR}. +# Language "C" is required for find_package(Threads). +project(gmock CXX C) +cmake_minimum_required(VERSION 2.6.2) + +# Adds Google Mock's and Google Test's header directories to the search path. +include_directories("${gmock_SOURCE_DIR}/include" + "${gmock_SOURCE_DIR}" + "${gtest_SOURCE_DIR}/include") + +######################################################################## +# +# Defines the gmock & gmock_main libraries. User tests should link +# with one of them. + +# Google Mock libraries. We build them using more strict warnings than what +# are used for other targets, to ensure that Google Mock can be compiled by +# a user aggressive about warnings. +cxx_library(gmock + "${cxx_strict}" + src/gmock-all.cc) + +cxx_library(gmock_main + "${cxx_strict}" + src/gmock-all.cc + src/gmock_main.cc) diff --git a/test/gmock/include/gmock/gmock-actions.h b/test/gmock/include/gmock/gmock-actions.h new file mode 100644 index 0000000..7e9708e --- /dev/null +++ b/test/gmock/include/gmock/gmock-actions.h @@ -0,0 +1,1078 @@ +// 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 implements some commonly used actions. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ + +#ifndef _WIN32_WCE +# include +#endif + +#include +#include + +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-port.h" + +namespace testing { + +// To implement an action Foo, define: +// 1. a class FooAction that implements the ActionInterface interface, and +// 2. a factory function that creates an Action object from a +// const FooAction*. +// +// The two-level delegation design follows that of Matcher, providing +// consistency for extension developers. It also eases ownership +// management as Action objects can now be copied like plain values. + +namespace internal { + +template +class ActionAdaptor; + +// BuiltInDefaultValue::Get() returns the "built-in" default +// value for type T, which is NULL when T is a pointer type, 0 when T +// is a numeric type, false when T is bool, or "" when T is string or +// std::string. For any other type T, this value is undefined and the +// function will abort the process. +template +class BuiltInDefaultValue { + public: + // This function returns true iff type T has a built-in default value. + static bool Exists() { return false; } + static T Get() { + Assert(false, __FILE__, __LINE__, + "Default action undefined for the function return type."); + return internal::Invalid(); + // The above statement will never be reached, but is required in + // order for this function to compile. + } +}; + +// This partial specialization says that we use the same built-in +// default value for T and const T. +template +class BuiltInDefaultValue { + public: + static bool Exists() { return BuiltInDefaultValue::Exists(); } + static T Get() { return BuiltInDefaultValue::Get(); } +}; + +// This partial specialization defines the default values for pointer +// types. +template +class BuiltInDefaultValue { + public: + static bool Exists() { return true; } + static T* Get() { return NULL; } +}; + +// The following specializations define the default values for +// specific types we care about. +#define GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(type, value) \ + template <> \ + class BuiltInDefaultValue { \ + public: \ + static bool Exists() { return true; } \ + static type Get() { return value; } \ + } + +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(void, ); // NOLINT +#if GTEST_HAS_GLOBAL_STRING +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::string, ""); +#endif // GTEST_HAS_GLOBAL_STRING +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::std::string, ""); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(bool, false); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned char, '\0'); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed char, '\0'); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(char, '\0'); + +// There's no need for a default action for signed wchar_t, as that +// type is the same as wchar_t for gcc, and invalid for MSVC. +// +// There's also no need for a default action for unsigned wchar_t, as +// that type is the same as unsigned int for gcc, and invalid for +// MSVC. +#if GMOCK_WCHAR_T_IS_NATIVE_ +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(wchar_t, 0U); // NOLINT +#endif + +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned short, 0U); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed short, 0); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned int, 0U); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed int, 0); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long, 0UL); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long, 0L); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(UInt64, 0); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(Int64, 0); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(float, 0); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0); + +#undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_ + +} // namespace internal + +// When an unexpected function call is encountered, Google Mock will +// let it return a default value if the user has specified one for its +// return type, or if the return type has a built-in default value; +// otherwise Google Mock won't know what value to return and will have +// to abort the process. +// +// The DefaultValue class allows a user to specify the +// default value for a type T that is both copyable and publicly +// destructible (i.e. anything that can be used as a function return +// type). The usage is: +// +// // Sets the default value for type T to be foo. +// DefaultValue::Set(foo); +template +class DefaultValue { + public: + // Sets the default value for type T; requires T to be + // copy-constructable and have a public destructor. + static void Set(T x) { + delete value_; + value_ = new T(x); + } + + // Unsets the default value for type T. + static void Clear() { + delete value_; + value_ = NULL; + } + + // Returns true iff the user has set the default value for type T. + static bool IsSet() { return value_ != NULL; } + + // Returns true if T has a default return value set by the user or there + // exists a built-in default value. + static bool Exists() { + return IsSet() || internal::BuiltInDefaultValue::Exists(); + } + + // Returns the default value for type T if the user has set one; + // otherwise returns the built-in default value if there is one; + // otherwise aborts the process. + static T Get() { + return value_ == NULL ? + internal::BuiltInDefaultValue::Get() : *value_; + } + + private: + static const T* value_; +}; + +// This partial specialization allows a user to set default values for +// reference types. +template +class DefaultValue { + public: + // Sets the default value for type T&. + static void Set(T& x) { // NOLINT + address_ = &x; + } + + // Unsets the default value for type T&. + static void Clear() { + address_ = NULL; + } + + // Returns true iff the user has set the default value for type T&. + static bool IsSet() { return address_ != NULL; } + + // Returns true if T has a default return value set by the user or there + // exists a built-in default value. + static bool Exists() { + return IsSet() || internal::BuiltInDefaultValue::Exists(); + } + + // Returns the default value for type T& if the user has set one; + // otherwise returns the built-in default value if there is one; + // otherwise aborts the process. + static T& Get() { + return address_ == NULL ? + internal::BuiltInDefaultValue::Get() : *address_; + } + + private: + static T* address_; +}; + +// This specialization allows DefaultValue::Get() to +// compile. +template <> +class DefaultValue { + public: + static bool Exists() { return true; } + static void Get() {} +}; + +// Points to the user-set default value for type T. +template +const T* DefaultValue::value_ = NULL; + +// Points to the user-set default value for type T&. +template +T* DefaultValue::address_ = NULL; + +// Implement this interface to define an action for function type F. +template +class ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + ActionInterface() {} + virtual ~ActionInterface() {} + + // Performs the action. This method is not const, as in general an + // action can have side effects and be stateful. For example, a + // get-the-next-element-from-the-collection action will need to + // remember the current element. + virtual Result Perform(const ArgumentTuple& args) = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionInterface); +}; + +// An Action is a copyable and IMMUTABLE (except by assignment) +// object that represents an action to be taken when a mock function +// of type F is called. The implementation of Action is just a +// linked_ptr to const ActionInterface, so copying is fairly cheap. +// Don't inherit from Action! +// +// You can view an object implementing ActionInterface as a +// concrete action (including its current state), and an Action +// object as a handle to it. +template +class Action { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + // Constructs a null Action. Needed for storing Action objects in + // STL containers. + Action() : impl_(NULL) {} + + // Constructs an Action from its implementation. A NULL impl is + // used to represent the "do-default" action. + explicit Action(ActionInterface* impl) : impl_(impl) {} + + // Copy constructor. + Action(const Action& action) : impl_(action.impl_) {} + + // This constructor allows us to turn an Action object into an + // Action, as long as F's arguments can be implicitly converted + // to Func's and Func's return type can be implicitly converted to + // F's. + template + explicit Action(const Action& action); + + // Returns true iff this is the DoDefault() action. + bool IsDoDefault() const { return impl_.get() == NULL; } + + // Performs the action. Note that this method is const even though + // the corresponding method in ActionInterface is not. The reason + // is that a const Action means that it cannot be re-bound to + // another concrete action, not that the concrete action it binds to + // cannot change state. (Think of the difference between a const + // pointer and a pointer to const.) + Result Perform(const ArgumentTuple& args) const { + internal::Assert( + !IsDoDefault(), __FILE__, __LINE__, + "You are using DoDefault() inside a composite action like " + "DoAll() or WithArgs(). This is not supported for technical " + "reasons. Please instead spell out the default action, or " + "assign the default action to an Action variable and use " + "the variable in various places."); + return impl_->Perform(args); + } + + private: + template + friend class internal::ActionAdaptor; + + internal::linked_ptr > impl_; +}; + +// The PolymorphicAction class template makes it easy to implement a +// polymorphic action (i.e. an action that can be used in mock +// functions of than one type, e.g. Return()). +// +// To define a polymorphic action, a user first provides a COPYABLE +// implementation class that has a Perform() method template: +// +// class FooAction { +// public: +// template +// Result Perform(const ArgumentTuple& args) const { +// // Processes the arguments and returns a result, using +// // tr1::get(args) to get the N-th (0-based) argument in the tuple. +// } +// ... +// }; +// +// Then the user creates the polymorphic action using +// MakePolymorphicAction(object) where object has type FooAction. See +// the definition of Return(void) and SetArgumentPointee(value) for +// complete examples. +template +class PolymorphicAction { + public: + explicit PolymorphicAction(const Impl& impl) : impl_(impl) {} + + template + operator Action() const { + return Action(new MonomorphicImpl(impl_)); + } + + private: + template + class MonomorphicImpl : public ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} + + virtual Result Perform(const ArgumentTuple& args) { + return impl_.template Perform(args); + } + + private: + Impl impl_; + + GTEST_DISALLOW_ASSIGN_(MonomorphicImpl); + }; + + Impl impl_; + + GTEST_DISALLOW_ASSIGN_(PolymorphicAction); +}; + +// Creates an Action from its implementation and returns it. The +// created Action object owns the implementation. +template +Action MakeAction(ActionInterface* impl) { + return Action(impl); +} + +// Creates a polymorphic action from its implementation. This is +// easier to use than the PolymorphicAction constructor as it +// doesn't require you to explicitly write the template argument, e.g. +// +// MakePolymorphicAction(foo); +// vs +// PolymorphicAction(foo); +template +inline PolymorphicAction MakePolymorphicAction(const Impl& impl) { + return PolymorphicAction(impl); +} + +namespace internal { + +// Allows an Action object to pose as an Action, as long as F2 +// and F1 are compatible. +template +class ActionAdaptor : public ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + explicit ActionAdaptor(const Action& from) : impl_(from.impl_) {} + + virtual Result Perform(const ArgumentTuple& args) { + return impl_->Perform(args); + } + + private: + const internal::linked_ptr > impl_; + + GTEST_DISALLOW_ASSIGN_(ActionAdaptor); +}; + +// Implements the polymorphic Return(x) action, which can be used in +// any function that returns the type of x, regardless of the argument +// types. +// +// Note: The value passed into Return must be converted into +// Function::Result when this action is cast to Action rather than +// when that action is performed. This is important in scenarios like +// +// MOCK_METHOD1(Method, T(U)); +// ... +// { +// Foo foo; +// X x(&foo); +// EXPECT_CALL(mock, Method(_)).WillOnce(Return(x)); +// } +// +// In the example above the variable x holds reference to foo which leaves +// scope and gets destroyed. If copying X just copies a reference to foo, +// that copy will be left with a hanging reference. If conversion to T +// makes a copy of foo, the above code is safe. To support that scenario, we +// need to make sure that the type conversion happens inside the EXPECT_CALL +// statement, and conversion of the result of Return to Action is a +// good place for that. +// +template +class ReturnAction { + public: + // Constructs a ReturnAction object from the value to be returned. + // 'value' is passed by value instead of by const reference in order + // to allow Return("string literal") to compile. + explicit ReturnAction(R value) : value_(value) {} + + // This template type conversion operator allows Return(x) to be + // used in ANY function that returns x's type. + template + operator Action() const { + // Assert statement belongs here because this is the best place to verify + // conditions on F. It produces the clearest error messages + // in most compilers. + // Impl really belongs in this scope as a local class but can't + // because MSVC produces duplicate symbols in different translation units + // in this case. Until MS fixes that bug we put Impl into the class scope + // and put the typedef both here (for use in assert statement) and + // in the Impl class. But both definitions must be the same. + typedef typename Function::Result Result; + GTEST_COMPILE_ASSERT_( + !internal::is_reference::value, + use_ReturnRef_instead_of_Return_to_return_a_reference); + return Action(new Impl(value_)); + } + + private: + // Implements the Return(x) action for a particular function type F. + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + // The implicit cast is necessary when Result has more than one + // single-argument constructor (e.g. Result is std::vector) and R + // has a type conversion operator template. In that case, value_(value) + // won't compile as the compiler doesn't known which constructor of + // Result to call. ImplicitCast_ forces the compiler to convert R to + // Result without considering explicit constructors, thus resolving the + // ambiguity. value_ is then initialized using its copy constructor. + explicit Impl(R value) + : value_(::testing::internal::ImplicitCast_(value)) {} + + virtual Result Perform(const ArgumentTuple&) { return value_; } + + private: + GTEST_COMPILE_ASSERT_(!internal::is_reference::value, + Result_cannot_be_a_reference_type); + Result value_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + R value_; + + GTEST_DISALLOW_ASSIGN_(ReturnAction); +}; + +// Implements the ReturnNull() action. +class ReturnNullAction { + public: + // Allows ReturnNull() to be used in any pointer-returning function. + template + static Result Perform(const ArgumentTuple&) { + GTEST_COMPILE_ASSERT_(internal::is_pointer::value, + ReturnNull_can_be_used_to_return_a_pointer_only); + return NULL; + } +}; + +// Implements the Return() action. +class ReturnVoidAction { + public: + // Allows Return() to be used in any void-returning function. + template + static void Perform(const ArgumentTuple&) { + CompileAssertTypesEqual(); + } +}; + +// Implements the polymorphic ReturnRef(x) action, which can be used +// in any function that returns a reference to the type of x, +// regardless of the argument types. +template +class ReturnRefAction { + public: + // Constructs a ReturnRefAction object from the reference to be returned. + explicit ReturnRefAction(T& ref) : ref_(ref) {} // NOLINT + + // This template type conversion operator allows ReturnRef(x) to be + // used in ANY function that returns a reference to x's type. + template + operator Action() const { + typedef typename Function::Result Result; + // Asserts that the function return type is a reference. This + // catches the user error of using ReturnRef(x) when Return(x) + // should be used, and generates some helpful error message. + GTEST_COMPILE_ASSERT_(internal::is_reference::value, + use_Return_instead_of_ReturnRef_to_return_a_value); + return Action(new Impl(ref_)); + } + + private: + // Implements the ReturnRef(x) action for a particular function type F. + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(T& ref) : ref_(ref) {} // NOLINT + + virtual Result Perform(const ArgumentTuple&) { + return ref_; + } + + private: + T& ref_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + T& ref_; + + GTEST_DISALLOW_ASSIGN_(ReturnRefAction); +}; + +// Implements the polymorphic ReturnRefOfCopy(x) action, which can be +// used in any function that returns a reference to the type of x, +// regardless of the argument types. +template +class ReturnRefOfCopyAction { + public: + // Constructs a ReturnRefOfCopyAction object from the reference to + // be returned. + explicit ReturnRefOfCopyAction(const T& value) : value_(value) {} // NOLINT + + // This template type conversion operator allows ReturnRefOfCopy(x) to be + // used in ANY function that returns a reference to x's type. + template + operator Action() const { + typedef typename Function::Result Result; + // Asserts that the function return type is a reference. This + // catches the user error of using ReturnRefOfCopy(x) when Return(x) + // should be used, and generates some helpful error message. + GTEST_COMPILE_ASSERT_( + internal::is_reference::value, + use_Return_instead_of_ReturnRefOfCopy_to_return_a_value); + return Action(new Impl(value_)); + } + + private: + // Implements the ReturnRefOfCopy(x) action for a particular function type F. + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const T& value) : value_(value) {} // NOLINT + + virtual Result Perform(const ArgumentTuple&) { + return value_; + } + + private: + T value_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + const T value_; + + GTEST_DISALLOW_ASSIGN_(ReturnRefOfCopyAction); +}; + +// Implements the polymorphic DoDefault() action. +class DoDefaultAction { + public: + // This template type conversion operator allows DoDefault() to be + // used in any function. + template + operator Action() const { return Action(NULL); } +}; + +// Implements the Assign action to set a given pointer referent to a +// particular value. +template +class AssignAction { + public: + AssignAction(T1* ptr, T2 value) : ptr_(ptr), value_(value) {} + + template + void Perform(const ArgumentTuple& /* args */) const { + *ptr_ = value_; + } + + private: + T1* const ptr_; + const T2 value_; + + GTEST_DISALLOW_ASSIGN_(AssignAction); +}; + +#if !GTEST_OS_WINDOWS_MOBILE + +// Implements the SetErrnoAndReturn action to simulate return from +// various system calls and libc functions. +template +class SetErrnoAndReturnAction { + public: + SetErrnoAndReturnAction(int errno_value, T result) + : errno_(errno_value), + result_(result) {} + template + Result Perform(const ArgumentTuple& /* args */) const { + errno = errno_; + return result_; + } + + private: + const int errno_; + const T result_; + + GTEST_DISALLOW_ASSIGN_(SetErrnoAndReturnAction); +}; + +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Implements the SetArgumentPointee(x) action for any function +// whose N-th argument (0-based) is a pointer to x's type. The +// template parameter kIsProto is true iff type A is ProtocolMessage, +// proto2::Message, or a sub-class of those. +template +class SetArgumentPointeeAction { + public: + // Constructs an action that sets the variable pointed to by the + // N-th function argument to 'value'. + explicit SetArgumentPointeeAction(const A& value) : value_(value) {} + + template + void Perform(const ArgumentTuple& args) const { + CompileAssertTypesEqual(); + *::std::tr1::get(args) = value_; + } + + private: + const A value_; + + GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction); +}; + +template +class SetArgumentPointeeAction { + public: + // Constructs an action that sets the variable pointed to by the + // N-th function argument to 'proto'. Both ProtocolMessage and + // proto2::Message have the CopyFrom() method, so the same + // implementation works for both. + explicit SetArgumentPointeeAction(const Proto& proto) : proto_(new Proto) { + proto_->CopyFrom(proto); + } + + template + void Perform(const ArgumentTuple& args) const { + CompileAssertTypesEqual(); + ::std::tr1::get(args)->CopyFrom(*proto_); + } + + private: + const internal::linked_ptr proto_; + + GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction); +}; + +// Implements the InvokeWithoutArgs(f) action. The template argument +// FunctionImpl is the implementation type of f, which can be either a +// function pointer or a functor. InvokeWithoutArgs(f) can be used as an +// Action as long as f's type is compatible with F (i.e. f can be +// assigned to a tr1::function). +template +class InvokeWithoutArgsAction { + public: + // The c'tor makes a copy of function_impl (either a function + // pointer or a functor). + explicit InvokeWithoutArgsAction(FunctionImpl function_impl) + : function_impl_(function_impl) {} + + // Allows InvokeWithoutArgs(f) to be used as any action whose type is + // compatible with f. + template + Result Perform(const ArgumentTuple&) { return function_impl_(); } + + private: + FunctionImpl function_impl_; + + GTEST_DISALLOW_ASSIGN_(InvokeWithoutArgsAction); +}; + +// Implements the InvokeWithoutArgs(object_ptr, &Class::Method) action. +template +class InvokeMethodWithoutArgsAction { + public: + InvokeMethodWithoutArgsAction(Class* obj_ptr, MethodPtr method_ptr) + : obj_ptr_(obj_ptr), method_ptr_(method_ptr) {} + + template + Result Perform(const ArgumentTuple&) const { + return (obj_ptr_->*method_ptr_)(); + } + + private: + Class* const obj_ptr_; + const MethodPtr method_ptr_; + + GTEST_DISALLOW_ASSIGN_(InvokeMethodWithoutArgsAction); +}; + +// Implements the IgnoreResult(action) action. +template +class IgnoreResultAction { + public: + explicit IgnoreResultAction(const A& action) : action_(action) {} + + template + operator Action() const { + // Assert statement belongs here because this is the best place to verify + // conditions on F. It produces the clearest error messages + // in most compilers. + // Impl really belongs in this scope as a local class but can't + // because MSVC produces duplicate symbols in different translation units + // in this case. Until MS fixes that bug we put Impl into the class scope + // and put the typedef both here (for use in assert statement) and + // in the Impl class. But both definitions must be the same. + typedef typename internal::Function::Result Result; + + // Asserts at compile time that F returns void. + CompileAssertTypesEqual(); + + return Action(new Impl(action_)); + } + + private: + template + class Impl : public ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const A& action) : action_(action) {} + + virtual void Perform(const ArgumentTuple& args) { + // Performs the action and ignores its result. + action_.Perform(args); + } + + private: + // Type OriginalFunction is the same as F except that its return + // type is IgnoredValue. + typedef typename internal::Function::MakeResultIgnoredValue + OriginalFunction; + + const Action action_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + const A action_; + + GTEST_DISALLOW_ASSIGN_(IgnoreResultAction); +}; + +// A ReferenceWrapper object represents a reference to type T, +// which can be either const or not. It can be explicitly converted +// from, and implicitly converted to, a T&. Unlike a reference, +// ReferenceWrapper can be copied and can survive template type +// inference. This is used to support by-reference arguments in the +// InvokeArgument(...) action. The idea was from "reference +// wrappers" in tr1, which we don't have in our source tree yet. +template +class ReferenceWrapper { + public: + // Constructs a ReferenceWrapper object from a T&. + explicit ReferenceWrapper(T& l_value) : pointer_(&l_value) {} // NOLINT + + // Allows a ReferenceWrapper object to be implicitly converted to + // a T&. + operator T&() const { return *pointer_; } + private: + T* pointer_; +}; + +// Allows the expression ByRef(x) to be printed as a reference to x. +template +void PrintTo(const ReferenceWrapper& ref, ::std::ostream* os) { + T& value = ref; + UniversalPrinter::Print(value, os); +} + +// Does two actions sequentially. Used for implementing the DoAll(a1, +// a2, ...) action. +template +class DoBothAction { + public: + DoBothAction(Action1 action1, Action2 action2) + : action1_(action1), action2_(action2) {} + + // This template type conversion operator allows DoAll(a1, ..., a_n) + // to be used in ANY function of compatible type. + template + operator Action() const { + return Action(new Impl(action1_, action2_)); + } + + private: + // Implements the DoAll(...) action for a particular function type F. + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + typedef typename Function::MakeResultVoid VoidResult; + + Impl(const Action& action1, const Action& action2) + : action1_(action1), action2_(action2) {} + + virtual Result Perform(const ArgumentTuple& args) { + action1_.Perform(args); + return action2_.Perform(args); + } + + private: + const Action action1_; + const Action action2_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + Action1 action1_; + Action2 action2_; + + GTEST_DISALLOW_ASSIGN_(DoBothAction); +}; + +} // namespace internal + +// An Unused object can be implicitly constructed from ANY value. +// This is handy when defining actions that ignore some or all of the +// mock function arguments. For example, given +// +// MOCK_METHOD3(Foo, double(const string& label, double x, double y)); +// MOCK_METHOD3(Bar, double(int index, double x, double y)); +// +// instead of +// +// double DistanceToOriginWithLabel(const string& label, double x, double y) { +// return sqrt(x*x + y*y); +// } +// double DistanceToOriginWithIndex(int index, double x, double y) { +// return sqrt(x*x + y*y); +// } +// ... +// EXEPCT_CALL(mock, Foo("abc", _, _)) +// .WillOnce(Invoke(DistanceToOriginWithLabel)); +// EXEPCT_CALL(mock, Bar(5, _, _)) +// .WillOnce(Invoke(DistanceToOriginWithIndex)); +// +// you could write +// +// // We can declare any uninteresting argument as Unused. +// double DistanceToOrigin(Unused, double x, double y) { +// return sqrt(x*x + y*y); +// } +// ... +// EXEPCT_CALL(mock, Foo("abc", _, _)).WillOnce(Invoke(DistanceToOrigin)); +// EXEPCT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin)); +typedef internal::IgnoredValue Unused; + +// This constructor allows us to turn an Action object into an +// Action, as long as To's arguments can be implicitly converted +// to From's and From's return type cann be implicitly converted to +// To's. +template +template +Action::Action(const Action& from) + : impl_(new internal::ActionAdaptor(from)) {} + +// Creates an action that returns 'value'. 'value' is passed by value +// instead of const reference - otherwise Return("string literal") +// will trigger a compiler error about using array as initializer. +template +internal::ReturnAction Return(R value) { + return internal::ReturnAction(value); +} + +// Creates an action that returns NULL. +inline PolymorphicAction ReturnNull() { + return MakePolymorphicAction(internal::ReturnNullAction()); +} + +// Creates an action that returns from a void function. +inline PolymorphicAction Return() { + return MakePolymorphicAction(internal::ReturnVoidAction()); +} + +// Creates an action that returns the reference to a variable. +template +inline internal::ReturnRefAction ReturnRef(R& x) { // NOLINT + return internal::ReturnRefAction(x); +} + +// Creates an action that returns the reference to a copy of the +// argument. The copy is created when the action is constructed and +// lives as long as the action. +template +inline internal::ReturnRefOfCopyAction ReturnRefOfCopy(const R& x) { + return internal::ReturnRefOfCopyAction(x); +} + +// Creates an action that does the default action for the give mock function. +inline internal::DoDefaultAction DoDefault() { + return internal::DoDefaultAction(); +} + +// Creates an action that sets the variable pointed by the N-th +// (0-based) function argument to 'value'. +template +PolymorphicAction< + internal::SetArgumentPointeeAction< + N, T, internal::IsAProtocolMessage::value> > +SetArgPointee(const T& x) { + return MakePolymorphicAction(internal::SetArgumentPointeeAction< + N, T, internal::IsAProtocolMessage::value>(x)); +} + +#if !((GTEST_GCC_VER_ && GTEST_GCC_VER_ < 40000) || GTEST_OS_SYMBIAN) +// This overload allows SetArgPointee() to accept a string literal. +// GCC prior to the version 4.0 and Symbian C++ compiler cannot distinguish +// this overload from the templated version and emit a compile error. +template +PolymorphicAction< + internal::SetArgumentPointeeAction > +SetArgPointee(const char* p) { + return MakePolymorphicAction(internal::SetArgumentPointeeAction< + N, const char*, false>(p)); +} + +template +PolymorphicAction< + internal::SetArgumentPointeeAction > +SetArgPointee(const wchar_t* p) { + return MakePolymorphicAction(internal::SetArgumentPointeeAction< + N, const wchar_t*, false>(p)); +} +#endif + +// The following version is DEPRECATED. +template +PolymorphicAction< + internal::SetArgumentPointeeAction< + N, T, internal::IsAProtocolMessage::value> > +SetArgumentPointee(const T& x) { + return MakePolymorphicAction(internal::SetArgumentPointeeAction< + N, T, internal::IsAProtocolMessage::value>(x)); +} + +// Creates an action that sets a pointer referent to a given value. +template +PolymorphicAction > Assign(T1* ptr, T2 val) { + return MakePolymorphicAction(internal::AssignAction(ptr, val)); +} + +#if !GTEST_OS_WINDOWS_MOBILE + +// Creates an action that sets errno and returns the appropriate error. +template +PolymorphicAction > +SetErrnoAndReturn(int errval, T result) { + return MakePolymorphicAction( + internal::SetErrnoAndReturnAction(errval, result)); +} + +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Various overloads for InvokeWithoutArgs(). + +// Creates an action that invokes 'function_impl' with no argument. +template +PolymorphicAction > +InvokeWithoutArgs(FunctionImpl function_impl) { + return MakePolymorphicAction( + internal::InvokeWithoutArgsAction(function_impl)); +} + +// Creates an action that invokes the given method on the given object +// with no argument. +template +PolymorphicAction > +InvokeWithoutArgs(Class* obj_ptr, MethodPtr method_ptr) { + return MakePolymorphicAction( + internal::InvokeMethodWithoutArgsAction( + obj_ptr, method_ptr)); +} + +// Creates an action that performs an_action and throws away its +// result. In other words, it changes the return type of an_action to +// void. an_action MUST NOT return void, or the code won't compile. +template +inline internal::IgnoreResultAction IgnoreResult(const A& an_action) { + return internal::IgnoreResultAction(an_action); +} + +// Creates a reference wrapper for the given L-value. If necessary, +// you can explicitly specify the type of the reference. For example, +// suppose 'derived' is an object of type Derived, ByRef(derived) +// would wrap a Derived&. If you want to wrap a const Base& instead, +// where Base is a base class of Derived, just write: +// +// ByRef(derived) +template +inline internal::ReferenceWrapper ByRef(T& l_value) { // NOLINT + return internal::ReferenceWrapper(l_value); +} + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ diff --git a/test/gmock/include/gmock/gmock-cardinalities.h b/test/gmock/include/gmock/gmock-cardinalities.h new file mode 100644 index 0000000..fc315f9 --- /dev/null +++ b/test/gmock/include/gmock/gmock-cardinalities.h @@ -0,0 +1,147 @@ +// 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 implements some commonly used cardinalities. More +// cardinalities can be defined by the user implementing the +// CardinalityInterface interface if necessary. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ + +#include +#include // NOLINT +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" + +namespace testing { + +// To implement a cardinality Foo, define: +// 1. a class FooCardinality that implements the +// CardinalityInterface interface, and +// 2. a factory function that creates a Cardinality object from a +// const FooCardinality*. +// +// The two-level delegation design follows that of Matcher, providing +// consistency for extension developers. It also eases ownership +// management as Cardinality objects can now be copied like plain values. + +// The implementation of a cardinality. +class CardinalityInterface { + public: + virtual ~CardinalityInterface() {} + + // Conservative estimate on the lower/upper bound of the number of + // calls allowed. + virtual int ConservativeLowerBound() const { return 0; } + virtual int ConservativeUpperBound() const { return INT_MAX; } + + // Returns true iff call_count calls will satisfy this cardinality. + virtual bool IsSatisfiedByCallCount(int call_count) const = 0; + + // Returns true iff call_count calls will saturate this cardinality. + virtual bool IsSaturatedByCallCount(int call_count) const = 0; + + // Describes self to an ostream. + virtual void DescribeTo(::std::ostream* os) const = 0; +}; + +// A Cardinality is a copyable and IMMUTABLE (except by assignment) +// object that specifies how many times a mock function is expected to +// be called. The implementation of Cardinality is just a linked_ptr +// to const CardinalityInterface, so copying is fairly cheap. +// Don't inherit from Cardinality! +class GTEST_API_ Cardinality { + public: + // Constructs a null cardinality. Needed for storing Cardinality + // objects in STL containers. + Cardinality() {} + + // Constructs a Cardinality from its implementation. + explicit Cardinality(const CardinalityInterface* impl) : impl_(impl) {} + + // Conservative estimate on the lower/upper bound of the number of + // calls allowed. + int ConservativeLowerBound() const { return impl_->ConservativeLowerBound(); } + int ConservativeUpperBound() const { return impl_->ConservativeUpperBound(); } + + // Returns true iff call_count calls will satisfy this cardinality. + bool IsSatisfiedByCallCount(int call_count) const { + return impl_->IsSatisfiedByCallCount(call_count); + } + + // Returns true iff call_count calls will saturate this cardinality. + bool IsSaturatedByCallCount(int call_count) const { + return impl_->IsSaturatedByCallCount(call_count); + } + + // Returns true iff call_count calls will over-saturate this + // cardinality, i.e. exceed the maximum number of allowed calls. + bool IsOverSaturatedByCallCount(int call_count) const { + return impl_->IsSaturatedByCallCount(call_count) && + !impl_->IsSatisfiedByCallCount(call_count); + } + + // Describes self to an ostream + void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } + + // Describes the given actual call count to an ostream. + static void DescribeActualCallCountTo(int actual_call_count, + ::std::ostream* os); + + private: + internal::linked_ptr impl_; +}; + +// Creates a cardinality that allows at least n calls. +GTEST_API_ Cardinality AtLeast(int n); + +// Creates a cardinality that allows at most n calls. +GTEST_API_ Cardinality AtMost(int n); + +// Creates a cardinality that allows any number of calls. +GTEST_API_ Cardinality AnyNumber(); + +// Creates a cardinality that allows between min and max calls. +GTEST_API_ Cardinality Between(int min, int max); + +// Creates a cardinality that allows exactly n calls. +GTEST_API_ Cardinality Exactly(int n); + +// Creates a cardinality from its implementation. +inline Cardinality MakeCardinality(const CardinalityInterface* c) { + return Cardinality(c); +} + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ diff --git a/test/gmock/include/gmock/gmock-generated-actions.h b/test/gmock/include/gmock/gmock-generated-actions.h new file mode 100644 index 0000000..2327393 --- /dev/null +++ b/test/gmock/include/gmock/gmock-generated-actions.h @@ -0,0 +1,2415 @@ +// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! + +// 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 implements some commonly used variadic actions. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ + +#include "gmock/gmock-actions.h" +#include "gmock/internal/gmock-port.h" + +namespace testing { +namespace internal { + +// InvokeHelper knows how to unpack an N-tuple and invoke an N-ary +// function or method with the unpacked values, where F is a function +// type that takes N arguments. +template +class InvokeHelper; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple<>&) { + return function(); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple<>&) { + return (obj_ptr->*method_ptr)(); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return function(get<0>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return (obj_ptr->*method_ptr)(get<0>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return function(get<0>(args), get<1>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return function(get<0>(args), get<1>(args), get<2>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), + get<3>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args), + get<4>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), + get<3>(args), get<4>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args), + get<4>(args), get<5>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), + get<3>(args), get<4>(args), get<5>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args), + get<4>(args), get<5>(args), get<6>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), + get<3>(args), get<4>(args), get<5>(args), get<6>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args), + get<4>(args), get<5>(args), get<6>(args), get<7>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), + get<3>(args), get<4>(args), get<5>(args), get<6>(args), get<7>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args), + get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), + get<3>(args), get<4>(args), get<5>(args), get<6>(args), get<7>(args), + get<8>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args), + get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args), + get<9>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), + get<3>(args), get<4>(args), get<5>(args), get<6>(args), get<7>(args), + get<8>(args), get<9>(args)); + } +}; + +// CallableHelper has static methods for invoking "callables", +// i.e. function pointers and functors. It uses overloading to +// provide a uniform interface for invoking different kinds of +// callables. In particular, you can use: +// +// CallableHelper::Call(callable, a1, a2, ..., an) +// +// to invoke an n-ary callable, where R is its return type. If an +// argument, say a2, needs to be passed by reference, you should write +// ByRef(a2) instead of a2 in the above expression. +template +class CallableHelper { + public: + // Calls a nullary callable. + template + static R Call(Function function) { return function(); } + + // Calls a unary callable. + + // We deliberately pass a1 by value instead of const reference here + // in case it is a C-string literal. If we had declared the + // parameter as 'const A1& a1' and write Call(function, "Hi"), the + // compiler would've thought A1 is 'char[3]', which causes trouble + // when you need to copy a value of type A1. By declaring the + // parameter as 'A1 a1', the compiler will correctly infer that A1 + // is 'const char*' when it sees Call(function, "Hi"). + // + // Since this function is defined inline, the compiler can get rid + // of the copying of the arguments. Therefore the performance won't + // be hurt. + template + static R Call(Function function, A1 a1) { return function(a1); } + + // Calls a binary callable. + template + static R Call(Function function, A1 a1, A2 a2) { + return function(a1, a2); + } + + // Calls a ternary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3) { + return function(a1, a2, a3); + } + + // Calls a 4-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4) { + return function(a1, a2, a3, a4); + } + + // Calls a 5-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + return function(a1, a2, a3, a4, a5); + } + + // Calls a 6-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { + return function(a1, a2, a3, a4, a5, a6); + } + + // Calls a 7-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7) { + return function(a1, a2, a3, a4, a5, a6, a7); + } + + // Calls a 8-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7, A8 a8) { + return function(a1, a2, a3, a4, a5, a6, a7, a8); + } + + // Calls a 9-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7, A8 a8, A9 a9) { + return function(a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + // Calls a 10-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7, A8 a8, A9 a9, A10 a10) { + return function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } +}; // class CallableHelper + +// An INTERNAL macro for extracting the type of a tuple field. It's +// subject to change without notice - DO NOT USE IN USER CODE! +#define GMOCK_FIELD_(Tuple, N) \ + typename ::std::tr1::tuple_element::type + +// SelectArgs::type is the +// type of an n-ary function whose i-th (1-based) argument type is the +// k{i}-th (0-based) field of ArgumentTuple, which must be a tuple +// type, and whose return type is Result. For example, +// SelectArgs, 0, 3>::type +// is int(bool, long). +// +// SelectArgs::Select(args) +// returns the selected fields (k1, k2, ..., k_n) of args as a tuple. +// For example, +// SelectArgs, 2, 0>::Select( +// ::std::tr1::make_tuple(true, 'a', 2.5)) +// returns ::std::tr1::tuple (2.5, true). +// +// The numbers in list k1, k2, ..., k_n must be >= 0, where n can be +// in the range [0, 10]. Duplicates are allowed and they don't have +// to be in an ascending or descending order. + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), + GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7), + GMOCK_FIELD_(ArgumentTuple, k8), GMOCK_FIELD_(ArgumentTuple, k9), + GMOCK_FIELD_(ArgumentTuple, k10)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + using ::std::tr1::get; + return SelectedArgs(get(args), get(args), get(args), + get(args), get(args), get(args), get(args), + get(args), get(args), get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& /* args */) { + using ::std::tr1::get; + return SelectedArgs(); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + using ::std::tr1::get; + return SelectedArgs(get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + using ::std::tr1::get; + return SelectedArgs(get(args), get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + using ::std::tr1::get; + return SelectedArgs(get(args), get(args), get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + using ::std::tr1::get; + return SelectedArgs(get(args), get(args), get(args), + get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + using ::std::tr1::get; + return SelectedArgs(get(args), get(args), get(args), + get(args), get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), + GMOCK_FIELD_(ArgumentTuple, k6)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + using ::std::tr1::get; + return SelectedArgs(get(args), get(args), get(args), + get(args), get(args), get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), + GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + using ::std::tr1::get; + return SelectedArgs(get(args), get(args), get(args), + get(args), get(args), get(args), get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), + GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7), + GMOCK_FIELD_(ArgumentTuple, k8)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + using ::std::tr1::get; + return SelectedArgs(get(args), get(args), get(args), + get(args), get(args), get(args), get(args), + get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), + GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7), + GMOCK_FIELD_(ArgumentTuple, k8), GMOCK_FIELD_(ArgumentTuple, k9)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + using ::std::tr1::get; + return SelectedArgs(get(args), get(args), get(args), + get(args), get(args), get(args), get(args), + get(args), get(args)); + } +}; + +#undef GMOCK_FIELD_ + +// Implements the WithArgs action. +template +class WithArgsAction { + public: + explicit WithArgsAction(const InnerAction& action) : action_(action) {} + + template + operator Action() const { return MakeAction(new Impl(action_)); } + + private: + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const InnerAction& action) : action_(action) {} + + virtual Result Perform(const ArgumentTuple& args) { + return action_.Perform(SelectArgs::Select(args)); + } + + private: + typedef typename SelectArgs::type InnerFunctionType; + + Action action_; + }; + + const InnerAction action_; + + GTEST_DISALLOW_ASSIGN_(WithArgsAction); +}; + +// A macro from the ACTION* family (defined later in this file) +// defines an action that can be used in a mock function. Typically, +// these actions only care about a subset of the arguments of the mock +// function. For example, if such an action only uses the second +// argument, it can be used in any mock function that takes >= 2 +// arguments where the type of the second argument is compatible. +// +// Therefore, the action implementation must be prepared to take more +// arguments than it needs. The ExcessiveArg type is used to +// represent those excessive arguments. In order to keep the compiler +// error messages tractable, we define it in the testing namespace +// instead of testing::internal. However, this is an INTERNAL TYPE +// and subject to change without notice, so a user MUST NOT USE THIS +// TYPE DIRECTLY. +struct ExcessiveArg {}; + +// A helper class needed for implementing the ACTION* macros. +template +class ActionHelper { + public: + static Result Perform(Impl* impl, const ::std::tr1::tuple<>& args) { + using ::std::tr1::get; + return impl->template gmock_PerformImpl<>(args, ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->template gmock_PerformImpl(args, get<0>(args), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->template gmock_PerformImpl(args, get<0>(args), + get<1>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->template gmock_PerformImpl(args, get<0>(args), + get<1>(args), get<2>(args), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->template gmock_PerformImpl(args, get<0>(args), + get<1>(args), get<2>(args), get<3>(args), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->template gmock_PerformImpl(args, + get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->template gmock_PerformImpl(args, + get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), + get<5>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->template gmock_PerformImpl(args, + get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), + get<5>(args), get<6>(args), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), + get<4>(args), get<5>(args), get<6>(args), get<7>(args), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), + get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), + get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args), + get<9>(args)); + } +}; + +} // namespace internal + +// Various overloads for Invoke(). + +// WithArgs(an_action) creates an action that passes +// the selected arguments of the mock function to an_action and +// performs it. It serves as an adaptor between actions with +// different argument lists. C++ doesn't support default arguments for +// function templates, so we have to overload it. +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +// Creates an action that does actions a1, a2, ..., sequentially in +// each invocation. +template +inline internal::DoBothAction +DoAll(Action1 a1, Action2 a2) { + return internal::DoBothAction(a1, a2); +} + +template +inline internal::DoBothAction > +DoAll(Action1 a1, Action2 a2, Action3 a3) { + return DoAll(a1, DoAll(a2, a3)); +} + +template +inline internal::DoBothAction > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4) { + return DoAll(a1, DoAll(a2, a3, a4)); +} + +template +inline internal::DoBothAction > > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5) { + return DoAll(a1, DoAll(a2, a3, a4, a5)); +} + +template +inline internal::DoBothAction > > > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6) { + return DoAll(a1, DoAll(a2, a3, a4, a5, a6)); +} + +template +inline internal::DoBothAction > > > > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, + Action7 a7) { + return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7)); +} + +template +inline internal::DoBothAction > > > > > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, + Action7 a7, Action8 a8) { + return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8)); +} + +template +inline internal::DoBothAction > > > > > > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, + Action7 a7, Action8 a8, Action9 a9) { + return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8, a9)); +} + +template +inline internal::DoBothAction > > > > > > > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, + Action7 a7, Action8 a8, Action9 a9, Action10 a10) { + return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8, a9, a10)); +} + +} // namespace testing + +// The ACTION* family of macros can be used in a namespace scope to +// define custom actions easily. The syntax: +// +// ACTION(name) { statements; } +// +// will define an action with the given name that executes the +// statements. The value returned by the statements will be used as +// the return value of the action. Inside the statements, you can +// refer to the K-th (0-based) argument of the mock function by +// 'argK', and refer to its type by 'argK_type'. For example: +// +// ACTION(IncrementArg1) { +// arg1_type temp = arg1; +// return ++(*temp); +// } +// +// allows you to write +// +// ...WillOnce(IncrementArg1()); +// +// You can also refer to the entire argument tuple and its type by +// 'args' and 'args_type', and refer to the mock function type and its +// return type by 'function_type' and 'return_type'. +// +// Note that you don't need to specify the types of the mock function +// arguments. However rest assured that your code is still type-safe: +// you'll get a compiler error if *arg1 doesn't support the ++ +// operator, or if the type of ++(*arg1) isn't compatible with the +// mock function's return type, for example. +// +// Sometimes you'll want to parameterize the action. For that you can use +// another macro: +// +// ACTION_P(name, param_name) { statements; } +// +// For example: +// +// ACTION_P(Add, n) { return arg0 + n; } +// +// will allow you to write: +// +// ...WillOnce(Add(5)); +// +// Note that you don't need to provide the type of the parameter +// either. If you need to reference the type of a parameter named +// 'foo', you can write 'foo_type'. For example, in the body of +// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type +// of 'n'. +// +// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P10 to support +// multi-parameter actions. +// +// For the purpose of typing, you can view +// +// ACTION_Pk(Foo, p1, ..., pk) { ... } +// +// as shorthand for +// +// template +// FooActionPk Foo(p1_type p1, ..., pk_type pk) { ... } +// +// In particular, you can provide the template type arguments +// explicitly when invoking Foo(), as in Foo(5, false); +// although usually you can rely on the compiler to infer the types +// for you automatically. You can assign the result of expression +// Foo(p1, ..., pk) to a variable of type FooActionPk. This can be useful when composing actions. +// +// You can also overload actions with different numbers of parameters: +// +// ACTION_P(Plus, a) { ... } +// ACTION_P2(Plus, a, b) { ... } +// +// While it's tempting to always use the ACTION* macros when defining +// a new action, you should also consider implementing ActionInterface +// or using MakePolymorphicAction() instead, especially if you need to +// use the action a lot. While these approaches require more work, +// they give you more control on the types of the mock function +// arguments and the action parameters, which in general leads to +// better compiler error messages that pay off in the long run. They +// also allow overloading actions based on parameter types (as opposed +// to just based on the number of parameters). +// +// CAVEAT: +// +// ACTION*() can only be used in a namespace scope. The reason is +// that C++ doesn't yet allow function-local types to be used to +// instantiate templates. The up-coming C++0x standard will fix this. +// Once that's done, we'll consider supporting using ACTION*() inside +// a function. +// +// MORE INFORMATION: +// +// To learn more about using these macros, please search for 'ACTION' +// on http://code.google.com/p/googlemock/wiki/CookBook. + +// An internal macro needed for implementing ACTION*(). +#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_\ + const args_type& args GTEST_ATTRIBUTE_UNUSED_, \ + arg0_type arg0 GTEST_ATTRIBUTE_UNUSED_, \ + arg1_type arg1 GTEST_ATTRIBUTE_UNUSED_, \ + arg2_type arg2 GTEST_ATTRIBUTE_UNUSED_, \ + arg3_type arg3 GTEST_ATTRIBUTE_UNUSED_, \ + arg4_type arg4 GTEST_ATTRIBUTE_UNUSED_, \ + arg5_type arg5 GTEST_ATTRIBUTE_UNUSED_, \ + arg6_type arg6 GTEST_ATTRIBUTE_UNUSED_, \ + arg7_type arg7 GTEST_ATTRIBUTE_UNUSED_, \ + arg8_type arg8 GTEST_ATTRIBUTE_UNUSED_, \ + arg9_type arg9 GTEST_ATTRIBUTE_UNUSED_ + +// 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(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::tr1::get(args)); +// } +// ... +// int n; +// EXPECT_CALL(mock, Foo(_, _)) +// .WillOnce(DuplicateArg<1, unsigned char>(&n)); +// +// To create an instance of an action template, write: +// +// ActionName(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(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(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. +#define GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(kind0, name0) kind0 name0 +#define GMOCK_INTERNAL_DECL_HAS_2_TEMPLATE_PARAMS(kind0, name0, kind1, \ + name1) kind0 name0, kind1 name1 +#define GMOCK_INTERNAL_DECL_HAS_3_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2) kind0 name0, kind1 name1, kind2 name2 +#define GMOCK_INTERNAL_DECL_HAS_4_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3) kind0 name0, kind1 name1, kind2 name2, \ + kind3 name3 +#define GMOCK_INTERNAL_DECL_HAS_5_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4) kind0 name0, kind1 name1, \ + kind2 name2, kind3 name3, kind4 name4 +#define GMOCK_INTERNAL_DECL_HAS_6_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5) kind0 name0, \ + kind1 name1, kind2 name2, kind3 name3, kind4 name4, kind5 name5 +#define GMOCK_INTERNAL_DECL_HAS_7_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ + name6) kind0 name0, kind1 name1, kind2 name2, kind3 name3, kind4 name4, \ + kind5 name5, kind6 name6 +#define GMOCK_INTERNAL_DECL_HAS_8_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ + kind7, name7) kind0 name0, kind1 name1, kind2 name2, kind3 name3, \ + kind4 name4, kind5 name5, kind6 name6, kind7 name7 +#define GMOCK_INTERNAL_DECL_HAS_9_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ + kind7, name7, kind8, name8) kind0 name0, kind1 name1, kind2 name2, \ + kind3 name3, kind4 name4, kind5 name5, kind6 name6, kind7 name7, \ + kind8 name8 +#define GMOCK_INTERNAL_DECL_HAS_10_TEMPLATE_PARAMS(kind0, name0, kind1, \ + name1, kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ + name6, kind7, name7, kind8, name8, kind9, name9) kind0 name0, \ + kind1 name1, kind2 name2, kind3 name3, kind4 name4, kind5 name5, \ + kind6 name6, kind7 name7, kind8 name8, kind9 name9 + +// Lists the template parameters. +#define GMOCK_INTERNAL_LIST_HAS_1_TEMPLATE_PARAMS(kind0, name0) name0 +#define GMOCK_INTERNAL_LIST_HAS_2_TEMPLATE_PARAMS(kind0, name0, kind1, \ + name1) name0, name1 +#define GMOCK_INTERNAL_LIST_HAS_3_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2) name0, name1, name2 +#define GMOCK_INTERNAL_LIST_HAS_4_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3) name0, name1, name2, name3 +#define GMOCK_INTERNAL_LIST_HAS_5_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4) name0, name1, name2, name3, \ + name4 +#define GMOCK_INTERNAL_LIST_HAS_6_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5) name0, name1, \ + name2, name3, name4, name5 +#define GMOCK_INTERNAL_LIST_HAS_7_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ + name6) name0, name1, name2, name3, name4, name5, name6 +#define GMOCK_INTERNAL_LIST_HAS_8_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ + kind7, name7) name0, name1, name2, name3, name4, name5, name6, name7 +#define GMOCK_INTERNAL_LIST_HAS_9_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ + kind7, name7, kind8, name8) name0, name1, name2, name3, name4, name5, \ + name6, name7, name8 +#define GMOCK_INTERNAL_LIST_HAS_10_TEMPLATE_PARAMS(kind0, name0, kind1, \ + name1, kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ + name6, kind7, name7, kind8, name8, kind9, name9) name0, name1, name2, \ + name3, name4, name5, name6, name7, name8, name9 + +// Declares the types of value parameters. +#define GMOCK_INTERNAL_DECL_TYPE_AND_0_VALUE_PARAMS() +#define GMOCK_INTERNAL_DECL_TYPE_AND_1_VALUE_PARAMS(p0) , typename p0##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_2_VALUE_PARAMS(p0, p1) , \ + typename p0##_type, typename p1##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_3_VALUE_PARAMS(p0, p1, p2) , \ + typename p0##_type, typename p1##_type, typename p2##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_4_VALUE_PARAMS(p0, p1, p2, p3) , \ + typename p0##_type, typename p1##_type, typename p2##_type, \ + typename p3##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) , \ + typename p0##_type, typename p1##_type, typename p2##_type, \ + typename p3##_type, typename p4##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) , \ + typename p0##_type, typename p1##_type, typename p2##_type, \ + typename p3##_type, typename p4##_type, typename p5##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6) , typename p0##_type, typename p1##_type, typename p2##_type, \ + typename p3##_type, typename p4##_type, typename p5##_type, \ + typename p6##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6, p7) , typename p0##_type, typename p1##_type, typename p2##_type, \ + typename p3##_type, typename p4##_type, typename p5##_type, \ + typename p6##_type, typename p7##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8) , typename p0##_type, typename p1##_type, typename p2##_type, \ + typename p3##_type, typename p4##_type, typename p5##_type, \ + typename p6##_type, typename p7##_type, typename p8##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8, p9) , typename p0##_type, typename p1##_type, \ + typename p2##_type, typename p3##_type, typename p4##_type, \ + typename p5##_type, typename p6##_type, typename p7##_type, \ + typename p8##_type, typename p9##_type + +// Initializes the value parameters. +#define GMOCK_INTERNAL_INIT_AND_0_VALUE_PARAMS()\ + () +#define GMOCK_INTERNAL_INIT_AND_1_VALUE_PARAMS(p0)\ + (p0##_type gmock_p0) : p0(gmock_p0) +#define GMOCK_INTERNAL_INIT_AND_2_VALUE_PARAMS(p0, p1)\ + (p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), p1(gmock_p1) +#define GMOCK_INTERNAL_INIT_AND_3_VALUE_PARAMS(p0, p1, p2)\ + (p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) +#define GMOCK_INTERNAL_INIT_AND_4_VALUE_PARAMS(p0, p1, p2, p3)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3) +#define GMOCK_INTERNAL_INIT_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4) +#define GMOCK_INTERNAL_INIT_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) +#define GMOCK_INTERNAL_INIT_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) +#define GMOCK_INTERNAL_INIT_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7) +#define GMOCK_INTERNAL_INIT_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ + p8(gmock_p8) +#define GMOCK_INTERNAL_INIT_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8, p9)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \ + p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ + p8(gmock_p8), p9(gmock_p9) + +// Declares the fields for storing the value parameters. +#define GMOCK_INTERNAL_DEFN_AND_0_VALUE_PARAMS() +#define GMOCK_INTERNAL_DEFN_AND_1_VALUE_PARAMS(p0) p0##_type p0; +#define GMOCK_INTERNAL_DEFN_AND_2_VALUE_PARAMS(p0, p1) p0##_type p0; \ + p1##_type p1; +#define GMOCK_INTERNAL_DEFN_AND_3_VALUE_PARAMS(p0, p1, p2) p0##_type p0; \ + p1##_type p1; p2##_type p2; +#define GMOCK_INTERNAL_DEFN_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0##_type p0; \ + p1##_type p1; p2##_type p2; p3##_type p3; +#define GMOCK_INTERNAL_DEFN_AND_5_VALUE_PARAMS(p0, p1, p2, p3, \ + p4) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; +#define GMOCK_INTERNAL_DEFN_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, \ + p5) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \ + p5##_type p5; +#define GMOCK_INTERNAL_DEFN_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \ + p5##_type p5; p6##_type p6; +#define GMOCK_INTERNAL_DEFN_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \ + p5##_type p5; p6##_type p6; p7##_type p7; +#define GMOCK_INTERNAL_DEFN_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; \ + p4##_type p4; p5##_type p5; p6##_type p6; p7##_type p7; p8##_type p8; +#define GMOCK_INTERNAL_DEFN_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8, p9) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; \ + p4##_type p4; p5##_type p5; p6##_type p6; p7##_type p7; p8##_type p8; \ + p9##_type p9; + +// Lists the value parameters. +#define GMOCK_INTERNAL_LIST_AND_0_VALUE_PARAMS() +#define GMOCK_INTERNAL_LIST_AND_1_VALUE_PARAMS(p0) p0 +#define GMOCK_INTERNAL_LIST_AND_2_VALUE_PARAMS(p0, p1) p0, p1 +#define GMOCK_INTERNAL_LIST_AND_3_VALUE_PARAMS(p0, p1, p2) p0, p1, p2 +#define GMOCK_INTERNAL_LIST_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0, p1, p2, p3 +#define GMOCK_INTERNAL_LIST_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) p0, p1, \ + p2, p3, p4 +#define GMOCK_INTERNAL_LIST_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) p0, \ + p1, p2, p3, p4, p5 +#define GMOCK_INTERNAL_LIST_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6) p0, p1, p2, p3, p4, p5, p6 +#define GMOCK_INTERNAL_LIST_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7) p0, p1, p2, p3, p4, p5, p6, p7 +#define GMOCK_INTERNAL_LIST_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8) p0, p1, p2, p3, p4, p5, p6, p7, p8 +#define GMOCK_INTERNAL_LIST_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8, p9) p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 + +// Lists the value parameter types. +#define GMOCK_INTERNAL_LIST_TYPE_AND_0_VALUE_PARAMS() +#define GMOCK_INTERNAL_LIST_TYPE_AND_1_VALUE_PARAMS(p0) , p0##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_2_VALUE_PARAMS(p0, p1) , p0##_type, \ + p1##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_3_VALUE_PARAMS(p0, p1, p2) , p0##_type, \ + p1##_type, p2##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_4_VALUE_PARAMS(p0, p1, p2, p3) , \ + p0##_type, p1##_type, p2##_type, p3##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) , \ + p0##_type, p1##_type, p2##_type, p3##_type, p4##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) , \ + p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type, \ + p6##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6, p7) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \ + p5##_type, p6##_type, p7##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \ + p5##_type, p6##_type, p7##_type, p8##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8, p9) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \ + p5##_type, p6##_type, p7##_type, p8##_type, p9##_type + +// Declares the value parameters. +#define GMOCK_INTERNAL_DECL_AND_0_VALUE_PARAMS() +#define GMOCK_INTERNAL_DECL_AND_1_VALUE_PARAMS(p0) p0##_type p0 +#define GMOCK_INTERNAL_DECL_AND_2_VALUE_PARAMS(p0, p1) p0##_type p0, \ + p1##_type p1 +#define GMOCK_INTERNAL_DECL_AND_3_VALUE_PARAMS(p0, p1, p2) p0##_type p0, \ + p1##_type p1, p2##_type p2 +#define GMOCK_INTERNAL_DECL_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0##_type p0, \ + p1##_type p1, p2##_type p2, p3##_type p3 +#define GMOCK_INTERNAL_DECL_AND_5_VALUE_PARAMS(p0, p1, p2, p3, \ + p4) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4 +#define GMOCK_INTERNAL_DECL_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, \ + p5) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \ + p5##_type p5 +#define GMOCK_INTERNAL_DECL_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \ + p5##_type p5, p6##_type p6 +#define GMOCK_INTERNAL_DECL_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \ + p5##_type p5, p6##_type p6, p7##_type p7 +#define GMOCK_INTERNAL_DECL_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8 +#define GMOCK_INTERNAL_DECL_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8, p9) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \ + p9##_type p9 + +// The suffix of the class template implementing the action template. +#define GMOCK_INTERNAL_COUNT_AND_0_VALUE_PARAMS() +#define GMOCK_INTERNAL_COUNT_AND_1_VALUE_PARAMS(p0) P +#define GMOCK_INTERNAL_COUNT_AND_2_VALUE_PARAMS(p0, p1) P2 +#define GMOCK_INTERNAL_COUNT_AND_3_VALUE_PARAMS(p0, p1, p2) P3 +#define GMOCK_INTERNAL_COUNT_AND_4_VALUE_PARAMS(p0, p1, p2, p3) P4 +#define GMOCK_INTERNAL_COUNT_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) P5 +#define GMOCK_INTERNAL_COUNT_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) P6 +#define GMOCK_INTERNAL_COUNT_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6) P7 +#define GMOCK_INTERNAL_COUNT_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7) P8 +#define GMOCK_INTERNAL_COUNT_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8) P9 +#define GMOCK_INTERNAL_COUNT_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8, p9) P10 + +// 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) + +#define ACTION_TEMPLATE(name, template_params, value_params)\ + template \ + class GMOCK_ACTION_CLASS_(name, value_params) {\ + public:\ + GMOCK_ACTION_CLASS_(name, value_params)\ + GMOCK_INTERNAL_INIT_##value_params {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + explicit gmock_Impl GMOCK_INTERNAL_INIT_##value_params {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + GMOCK_INTERNAL_DEFN_##value_params\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(\ + new gmock_Impl(GMOCK_INTERNAL_LIST_##value_params));\ + }\ + GMOCK_INTERNAL_DEFN_##value_params\ + private:\ + GTEST_DISALLOW_ASSIGN_(GMOCK_ACTION_CLASS_(name, value_params));\ + };\ + template \ + 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 \ + template \ + template \ + typename ::testing::internal::Function::Result\ + 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 + +#define ACTION(name)\ + class name##Action {\ + public:\ + name##Action() {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl() {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl());\ + }\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##Action);\ + };\ + inline name##Action name() {\ + return name##Action();\ + }\ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##Action::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P(name, p0)\ + template \ + class name##ActionP {\ + public:\ + name##ActionP(p0##_type gmock_p0) : p0(gmock_p0) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + explicit gmock_Impl(p0##_type gmock_p0) : p0(gmock_p0) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0));\ + }\ + p0##_type p0;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP);\ + };\ + template \ + inline name##ActionP name(p0##_type p0) {\ + return name##ActionP(p0);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P2(name, p0, p1)\ + template \ + class name##ActionP2 {\ + public:\ + name##ActionP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ + p1(gmock_p1) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ + p1(gmock_p1) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP2);\ + };\ + template \ + inline name##ActionP2 name(p0##_type p0, \ + p1##_type p1) {\ + return name##ActionP2(p0, p1);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP2::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P3(name, p0, p1, p2)\ + template \ + class name##ActionP3 {\ + public:\ + name##ActionP3(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP3);\ + };\ + template \ + inline name##ActionP3 name(p0##_type p0, \ + p1##_type p1, p2##_type p2) {\ + return name##ActionP3(p0, p1, p2);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP3::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P4(name, p0, p1, p2, p3)\ + template \ + class name##ActionP4 {\ + public:\ + name##ActionP4(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP4);\ + };\ + template \ + inline name##ActionP4 name(p0##_type p0, p1##_type p1, p2##_type p2, \ + p3##_type p3) {\ + return name##ActionP4(p0, p1, \ + p2, p3);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP4::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P5(name, p0, p1, p2, p3, p4)\ + template \ + class name##ActionP5 {\ + public:\ + name##ActionP5(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, \ + p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4) : p0(gmock_p0), \ + p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP5);\ + };\ + template \ + inline name##ActionP5 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4) {\ + return name##ActionP5(p0, p1, p2, p3, p4);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP5::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P6(name, p0, p1, p2, p3, p4, p5)\ + template \ + class name##ActionP6 {\ + public:\ + name##ActionP6(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP6);\ + };\ + template \ + inline name##ActionP6 name(p0##_type p0, p1##_type p1, p2##_type p2, \ + p3##_type p3, p4##_type p4, p5##_type p5) {\ + return name##ActionP6(p0, p1, p2, p3, p4, p5);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP6::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P7(name, p0, p1, p2, p3, p4, p5, p6)\ + template \ + class name##ActionP7 {\ + public:\ + name##ActionP7(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), \ + p6(gmock_p6) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ + p6));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP7);\ + };\ + template \ + inline name##ActionP7 name(p0##_type p0, p1##_type p1, \ + p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ + p6##_type p6) {\ + return name##ActionP7(p0, p1, p2, p3, p4, p5, p6);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP7::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P8(name, p0, p1, p2, p3, p4, p5, p6, p7)\ + template \ + class name##ActionP8 {\ + public:\ + name##ActionP8(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, \ + p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7) : p0(gmock_p0), \ + p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), \ + p5(gmock_p5), p6(gmock_p6), p7(gmock_p7) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ + p6, p7));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP8);\ + };\ + template \ + inline name##ActionP8 name(p0##_type p0, \ + p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ + p6##_type p6, p7##_type p7) {\ + return name##ActionP8(p0, p1, p2, p3, p4, p5, \ + p6, p7);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP8::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8)\ + template \ + class name##ActionP9 {\ + public:\ + name##ActionP9(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ + p8(gmock_p8) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7), p8(gmock_p8) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP9);\ + };\ + template \ + inline name##ActionP9 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, \ + p8##_type p8) {\ + return name##ActionP9(p0, p1, p2, \ + p3, p4, p5, p6, p7, p8);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP9::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)\ + template \ + class name##ActionP10 {\ + public:\ + name##ActionP10(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8, p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \ + p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + p9##_type p9;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8, p9));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + p9##_type p9;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP10);\ + };\ + template \ + inline name##ActionP10 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \ + p9##_type p9) {\ + return name##ActionP10(p0, \ + p1, p2, p3, p4, p5, p6, p7, p8, p9);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP10::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 + +// Various overloads for InvokeArgument(). +// +// The InvokeArgument(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 ByRef(). For +// example, +// +// InvokeArgument<1>(5, string("Hello"), ByRef(foo)) +// +// passes 5 and string("Hello") by value, and passes foo by +// reference. +// +// 2. If the callable takes an argument by reference but ByRef() 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. + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_0_VALUE_PARAMS()) { + return internal::CallableHelper::Call( + ::std::tr1::get(args)); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_1_VALUE_PARAMS(p0)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_2_VALUE_PARAMS(p0, p1)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_3_VALUE_PARAMS(p0, p1, p2)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_4_VALUE_PARAMS(p0, p1, p2, p3)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3, p4); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3, p4, p5); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3, p4, p5, p6); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3, p4, p5, p6, p7); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3, p4, p5, p6, p7, p8); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); +} + +// Various overloads for ReturnNew(). +// +// The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new +// instance of type T, constructed on the heap with constructor arguments +// a1, a2, ..., and a_k. The caller assumes ownership of the returned value. +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_0_VALUE_PARAMS()) { + return new T(); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_1_VALUE_PARAMS(p0)) { + return new T(p0); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_2_VALUE_PARAMS(p0, p1)) { + return new T(p0, p1); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_3_VALUE_PARAMS(p0, p1, p2)) { + return new T(p0, p1, p2); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_4_VALUE_PARAMS(p0, p1, p2, p3)) { + return new T(p0, p1, p2, p3); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) { + return new T(p0, p1, p2, p3, p4); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) { + return new T(p0, p1, p2, p3, p4, p5); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) { + return new T(p0, p1, p2, p3, p4, p5, p6); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) { + return new T(p0, p1, p2, p3, p4, p5, p6, p7); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) { + return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) { + return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/test/gmock/include/gmock/gmock-generated-actions.h.pump b/test/gmock/include/gmock/gmock-generated-actions.h.pump new file mode 100644 index 0000000..8e2b573 --- /dev/null +++ b/test/gmock/include/gmock/gmock-generated-actions.h.pump @@ -0,0 +1,821 @@ +$$ -*- 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. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements some commonly used variadic actions. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ + +#include "gmock/gmock-actions.h" +#include "gmock/internal/gmock-port.h" + +namespace testing { +namespace internal { + +// InvokeHelper knows how to unpack an N-tuple and invoke an N-ary +// function or method with the unpacked values, where F is a function +// type that takes N arguments. +template +class InvokeHelper; + + +$range i 0..n +$for i [[ +$range j 1..i +$var types = [[$for j [[, typename A$j]]]] +$var as = [[$for j, [[A$j]]]] +$var args = [[$if i==0 [[]] $else [[ args]]]] +$var import = [[$if i==0 [[]] $else [[ + using ::std::tr1::get; + +]]]] +$var gets = [[$for j, [[get<$(j - 1)>(args)]]]] +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple<$as>&$args) { +$import return function($gets); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple<$as>&$args) { +$import return (obj_ptr->*method_ptr)($gets); + } +}; + + +]] +// CallableHelper has static methods for invoking "callables", +// i.e. function pointers and functors. It uses overloading to +// provide a uniform interface for invoking different kinds of +// callables. In particular, you can use: +// +// CallableHelper::Call(callable, a1, a2, ..., an) +// +// to invoke an n-ary callable, where R is its return type. If an +// argument, say a2, needs to be passed by reference, you should write +// ByRef(a2) instead of a2 in the above expression. +template +class CallableHelper { + public: + // Calls a nullary callable. + template + static R Call(Function function) { return function(); } + + // Calls a unary callable. + + // We deliberately pass a1 by value instead of const reference here + // in case it is a C-string literal. If we had declared the + // parameter as 'const A1& a1' and write Call(function, "Hi"), the + // compiler would've thought A1 is 'char[3]', which causes trouble + // when you need to copy a value of type A1. By declaring the + // parameter as 'A1 a1', the compiler will correctly infer that A1 + // is 'const char*' when it sees Call(function, "Hi"). + // + // Since this function is defined inline, the compiler can get rid + // of the copying of the arguments. Therefore the performance won't + // be hurt. + template + static R Call(Function function, A1 a1) { return function(a1); } + +$range i 2..n +$for i +[[ +$var arity = [[$if i==2 [[binary]] $elif i==3 [[ternary]] $else [[$i-ary]]]] + + // Calls a $arity callable. + +$range j 1..i +$var typename_As = [[$for j, [[typename A$j]]]] +$var Aas = [[$for j, [[A$j a$j]]]] +$var as = [[$for j, [[a$j]]]] +$var typename_Ts = [[$for j, [[typename T$j]]]] +$var Ts = [[$for j, [[T$j]]]] + template + static R Call(Function function, $Aas) { + return function($as); + } + +]] +}; // class CallableHelper + +// An INTERNAL macro for extracting the type of a tuple field. It's +// subject to change without notice - DO NOT USE IN USER CODE! +#define GMOCK_FIELD_(Tuple, N) \ + typename ::std::tr1::tuple_element::type + +$range i 1..n + +// SelectArgs::type is the +// type of an n-ary function whose i-th (1-based) argument type is the +// k{i}-th (0-based) field of ArgumentTuple, which must be a tuple +// type, and whose return type is Result. For example, +// SelectArgs, 0, 3>::type +// is int(bool, long). +// +// SelectArgs::Select(args) +// returns the selected fields (k1, k2, ..., k_n) of args as a tuple. +// For example, +// SelectArgs, 2, 0>::Select( +// ::std::tr1::make_tuple(true, 'a', 2.5)) +// returns ::std::tr1::tuple (2.5, true). +// +// The numbers in list k1, k2, ..., k_n must be >= 0, where n can be +// in the range [0, $n]. Duplicates are allowed and they don't have +// to be in an ascending or descending order. + +template +class SelectArgs { + public: + typedef Result type($for i, [[GMOCK_FIELD_(ArgumentTuple, k$i)]]); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + using ::std::tr1::get; + return SelectedArgs($for i, [[get(args)]]); + } +}; + + +$for i [[ +$range j 1..n +$range j1 1..i-1 +template +class SelectArgs { + public: + typedef Result type($for j1, [[GMOCK_FIELD_(ArgumentTuple, k$j1)]]); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& [[]] +$if i == 1 [[/* args */]] $else [[args]]) { + using ::std::tr1::get; + return SelectedArgs($for j1, [[get(args)]]); + } +}; + + +]] +#undef GMOCK_FIELD_ + +$var ks = [[$for i, [[k$i]]]] + +// Implements the WithArgs action. +template +class WithArgsAction { + public: + explicit WithArgsAction(const InnerAction& action) : action_(action) {} + + template + operator Action() const { return MakeAction(new Impl(action_)); } + + private: + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const InnerAction& action) : action_(action) {} + + virtual Result Perform(const ArgumentTuple& args) { + return action_.Perform(SelectArgs::Select(args)); + } + + private: + typedef typename SelectArgs::type InnerFunctionType; + + Action action_; + }; + + const InnerAction action_; + + GTEST_DISALLOW_ASSIGN_(WithArgsAction); +}; + +// A macro from the ACTION* family (defined later in this file) +// defines an action that can be used in a mock function. Typically, +// these actions only care about a subset of the arguments of the mock +// function. For example, if such an action only uses the second +// argument, it can be used in any mock function that takes >= 2 +// arguments where the type of the second argument is compatible. +// +// Therefore, the action implementation must be prepared to take more +// arguments than it needs. The ExcessiveArg type is used to +// represent those excessive arguments. In order to keep the compiler +// error messages tractable, we define it in the testing namespace +// instead of testing::internal. However, this is an INTERNAL TYPE +// and subject to change without notice, so a user MUST NOT USE THIS +// TYPE DIRECTLY. +struct ExcessiveArg {}; + +// A helper class needed for implementing the ACTION* macros. +template +class ActionHelper { + public: +$range i 0..n +$for i + +[[ +$var template = [[$if i==0 [[]] $else [[ +$range j 0..i-1 + template <$for j, [[typename A$j]]> +]]]] +$range j 0..i-1 +$var As = [[$for j, [[A$j]]]] +$var as = [[$for j, [[get<$j>(args)]]]] +$range k 1..n-i +$var eas = [[$for k, [[ExcessiveArg()]]]] +$var arg_list = [[$if (i==0) | (i==n) [[$as$eas]] $else [[$as, $eas]]]] +$template + static Result Perform(Impl* impl, const ::std::tr1::tuple<$As>& args) { + using ::std::tr1::get; + return impl->template gmock_PerformImpl<$As>(args, $arg_list); + } + +]] +}; + +} // namespace internal + +// Various overloads for Invoke(). + +// WithArgs(an_action) creates an action that passes +// the selected arguments of the mock function to an_action and +// performs it. It serves as an adaptor between actions with +// different argument lists. C++ doesn't support default arguments for +// function templates, so we have to overload it. + +$range i 1..n +$for i [[ +$range j 1..i +template <$for j [[int k$j, ]]typename InnerAction> +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + + +]] +// Creates an action that does actions a1, a2, ..., sequentially in +// each invocation. +$range i 2..n +$for i [[ +$range j 2..i +$var types = [[$for j, [[typename Action$j]]]] +$var Aas = [[$for j [[, Action$j a$j]]]] + +template +$range k 1..i-1 + +inline $for k [[internal::DoBothAction]] + +DoAll(Action1 a1$Aas) { +$if i==2 [[ + + return internal::DoBothAction(a1, a2); +]] $else [[ +$range j2 2..i + + return DoAll(a1, DoAll($for j2, [[a$j2]])); +]] + +} + +]] + +} // namespace testing + +// The ACTION* family of macros can be used in a namespace scope to +// define custom actions easily. The syntax: +// +// ACTION(name) { statements; } +// +// will define an action with the given name that executes the +// statements. The value returned by the statements will be used as +// the return value of the action. Inside the statements, you can +// refer to the K-th (0-based) argument of the mock function by +// 'argK', and refer to its type by 'argK_type'. For example: +// +// ACTION(IncrementArg1) { +// arg1_type temp = arg1; +// return ++(*temp); +// } +// +// allows you to write +// +// ...WillOnce(IncrementArg1()); +// +// You can also refer to the entire argument tuple and its type by +// 'args' and 'args_type', and refer to the mock function type and its +// return type by 'function_type' and 'return_type'. +// +// Note that you don't need to specify the types of the mock function +// arguments. However rest assured that your code is still type-safe: +// you'll get a compiler error if *arg1 doesn't support the ++ +// operator, or if the type of ++(*arg1) isn't compatible with the +// mock function's return type, for example. +// +// Sometimes you'll want to parameterize the action. For that you can use +// another macro: +// +// ACTION_P(name, param_name) { statements; } +// +// For example: +// +// ACTION_P(Add, n) { return arg0 + n; } +// +// will allow you to write: +// +// ...WillOnce(Add(5)); +// +// Note that you don't need to provide the type of the parameter +// either. If you need to reference the type of a parameter named +// 'foo', you can write 'foo_type'. For example, in the body of +// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type +// of 'n'. +// +// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P$n to support +// multi-parameter actions. +// +// For the purpose of typing, you can view +// +// ACTION_Pk(Foo, p1, ..., pk) { ... } +// +// as shorthand for +// +// template +// FooActionPk Foo(p1_type p1, ..., pk_type pk) { ... } +// +// In particular, you can provide the template type arguments +// explicitly when invoking Foo(), as in Foo(5, false); +// although usually you can rely on the compiler to infer the types +// for you automatically. You can assign the result of expression +// Foo(p1, ..., pk) to a variable of type FooActionPk. This can be useful when composing actions. +// +// You can also overload actions with different numbers of parameters: +// +// ACTION_P(Plus, a) { ... } +// ACTION_P2(Plus, a, b) { ... } +// +// While it's tempting to always use the ACTION* macros when defining +// a new action, you should also consider implementing ActionInterface +// or using MakePolymorphicAction() instead, especially if you need to +// use the action a lot. While these approaches require more work, +// they give you more control on the types of the mock function +// arguments and the action parameters, which in general leads to +// better compiler error messages that pay off in the long run. They +// also allow overloading actions based on parameter types (as opposed +// to just based on the number of parameters). +// +// CAVEAT: +// +// ACTION*() can only be used in a namespace scope. The reason is +// that C++ doesn't yet allow function-local types to be used to +// instantiate templates. The up-coming C++0x standard will fix this. +// Once that's done, we'll consider supporting using ACTION*() inside +// a function. +// +// MORE INFORMATION: +// +// To learn more about using these macros, please search for 'ACTION' +// on http://code.google.com/p/googlemock/wiki/CookBook. + +$range i 0..n +$range k 0..n-1 + +// An internal macro needed for implementing ACTION*(). +#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_\ + const args_type& args GTEST_ATTRIBUTE_UNUSED_ +$for k [[, \ + arg$k[[]]_type arg$k GTEST_ATTRIBUTE_UNUSED_]] + + +// 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(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::tr1::get(args)); +// } +// ... +// int n; +// EXPECT_CALL(mock, Foo(_, _)) +// .WillOnce(DuplicateArg<1, unsigned char>(&n)); +// +// To create an instance of an action template, write: +// +// ActionName(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(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(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(gmock_p$j)]] + + +]] + +// 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 \ + class GMOCK_ACTION_CLASS_(name, value_params) {\ + public:\ + GMOCK_ACTION_CLASS_(name, value_params)\ + GMOCK_INTERNAL_INIT_##value_params {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + explicit gmock_Impl GMOCK_INTERNAL_INIT_##value_params {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template <$for k, [[typename arg$k[[]]_type]]>\ + return_type gmock_PerformImpl(const args_type& args[[]] +$for k [[, arg$k[[]]_type arg$k]]) const;\ + GMOCK_INTERNAL_DEFN_##value_params\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(\ + new gmock_Impl(GMOCK_INTERNAL_LIST_##value_params));\ + }\ + GMOCK_INTERNAL_DEFN_##value_params\ + private:\ + GTEST_DISALLOW_ASSIGN_(GMOCK_ACTION_CLASS_(name, value_params));\ + };\ + template \ + 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 \ + template \ + template \ + typename ::testing::internal::Function::Result\ + 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 + +$for i + +[[ +$var template = [[$if i==0 [[]] $else [[ +$range j 0..i-1 + + template <$for j, [[typename p$j##_type]]>\ +]]]] +$var class_name = [[name##Action[[$if i==0 [[]] $elif i==1 [[P]] + $else [[P$i]]]]]] +$range j 0..i-1 +$var ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]] +$var param_types_and_names = [[$for j, [[p$j##_type p$j]]]] +$var inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] +$var param_field_decls = [[$for j +[[ + + p$j##_type p$j;\ +]]]] +$var param_field_decls2 = [[$for j +[[ + + p$j##_type p$j;\ +]]]] +$var params = [[$for j, [[p$j]]]] +$var param_types = [[$if i==0 [[]] $else [[<$for j, [[p$j##_type]]>]]]] +$var typename_arg_types = [[$for k, [[typename arg$k[[]]_type]]]] +$var arg_types_and_names = [[$for k, [[arg$k[[]]_type arg$k]]]] +$var macro_name = [[$if i==0 [[ACTION]] $elif i==1 [[ACTION_P]] + $else [[ACTION_P$i]]]] + +#define $macro_name(name$for j [[, p$j]])\$template + class $class_name {\ + public:\ + $class_name($ctor_param_list)$inits {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + [[$if i==1 [[explicit ]]]]gmock_Impl($ctor_param_list)$inits {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template <$typename_arg_types>\ + return_type gmock_PerformImpl(const args_type& args, [[]] +$arg_types_and_names) const;\$param_field_decls + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl($params));\ + }\$param_field_decls2 + private:\ + GTEST_DISALLOW_ASSIGN_($class_name);\ + };\$template + inline $class_name$param_types name($param_types_and_names) {\ + return $class_name$param_types($params);\ + }\$template + template \ + template <$typename_arg_types>\ + typename ::testing::internal::Function::Result\ + $class_name$param_types::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const +]] +$$ } // This meta comment fixes auto-indentation in Emacs. It won't +$$ // show up in the generated code. + + +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 + +// Various overloads for InvokeArgument(). +// +// The InvokeArgument(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 ByRef(). For +// example, +// +// InvokeArgument<1>(5, string("Hello"), ByRef(foo)) +// +// passes 5 and string("Hello") by value, and passes foo by +// reference. +// +// 2. If the callable takes an argument by reference but ByRef() 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. + +$range i 0..n +$for i [[ +$range j 0..i-1 + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]])) { + return internal::CallableHelper::Call( + ::std::tr1::get(args)$for j [[, p$j]]); +} + +]] + +// Various overloads for ReturnNew(). +// +// The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new +// instance of type T, constructed on the heap with constructor arguments +// a1, a2, ..., and a_k. The caller assumes ownership of the returned value. +$range i 0..n +$for i [[ +$range j 0..i-1 +$var ps = [[$for j, [[p$j]]]] + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_$i[[]]_VALUE_PARAMS($ps)) { + return new T($ps); +} + +]] + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/test/gmock/include/gmock/gmock-generated-function-mockers.h b/test/gmock/include/gmock/gmock-generated-function-mockers.h new file mode 100644 index 0000000..577fd9e --- /dev/null +++ b/test/gmock/include/gmock/gmock-generated-function-mockers.h @@ -0,0 +1,991 @@ +// This file was GENERATED by command: +// pump.py gmock-generated-function-mockers.h.pump +// DO NOT EDIT BY HAND!!! + +// 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 implements function mockers of various arities. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ + +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-internal-utils.h" + +namespace testing { +namespace internal { + +template +class FunctionMockerBase; + +// Note: class FunctionMocker really belongs to the ::testing +// namespace. However if we define it in ::testing, MSVC will +// complain when classes in ::testing::internal declare it as a +// friend class template. To workaround this compiler bug, we define +// FunctionMocker in ::testing::internal and import it into ::testing. +template +class FunctionMocker; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With() { + return this->current_spec(); + } + + R Invoke() { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple()); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1) { + this->current_spec().SetMatchers(::std::tr1::make_tuple(m1)); + return this->current_spec(); + } + + R Invoke(A1 a1) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2) { + this->current_spec().SetMatchers(::std::tr1::make_tuple(m1, m2)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3) { + this->current_spec().SetMatchers(::std::tr1::make_tuple(m1, m2, m3)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4) { + this->current_spec().SetMatchers(::std::tr1::make_tuple(m1, m2, m3, m4)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4, A5); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4, const Matcher& m5) { + this->current_spec().SetMatchers(::std::tr1::make_tuple(m1, m2, m3, m4, + m5)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4, A5, A6); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4, const Matcher& m5, + const Matcher& m6) { + this->current_spec().SetMatchers(::std::tr1::make_tuple(m1, m2, m3, m4, m5, + m6)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4, A5, A6, A7); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4, const Matcher& m5, + const Matcher& m6, const Matcher& m7) { + this->current_spec().SetMatchers(::std::tr1::make_tuple(m1, m2, m3, m4, m5, + m6, m7)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4, A5, A6, A7, A8); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4, const Matcher& m5, + const Matcher& m6, const Matcher& m7, const Matcher& m8) { + this->current_spec().SetMatchers(::std::tr1::make_tuple(m1, m2, m3, m4, m5, + m6, m7, m8)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4, A5, A6, A7, A8, A9); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4, const Matcher& m5, + const Matcher& m6, const Matcher& m7, const Matcher& m8, + const Matcher& m9) { + this->current_spec().SetMatchers(::std::tr1::make_tuple(m1, m2, m3, m4, m5, + m6, m7, m8, m9)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, a9)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4, const Matcher& m5, + const Matcher& m6, const Matcher& m7, const Matcher& m8, + const Matcher& m9, const Matcher& m10) { + this->current_spec().SetMatchers(::std::tr1::make_tuple(m1, m2, m3, m4, m5, + m6, m7, m8, m9, m10)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, + A10 a10) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10)); + } +}; + +} // namespace internal + +// The style guide prohibits "using" statements in a namespace scope +// inside a header file. However, the FunctionMocker class template +// is meant to be defined in the ::testing namespace. The following +// line is just a trick for working around a bug in MSVC 8.0, which +// cannot handle it if we define FunctionMocker in ::testing. +using internal::FunctionMocker; + +// GMOCK_RESULT_(tn, F) expands to the result type of function type F. +// We define this as a variadic macro in case F contains unprotected +// commas (the same reason that we use variadic macros in other places +// in this file). +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_RESULT_(tn, ...) \ + tn ::testing::internal::Function<__VA_ARGS__>::Result + +// The type of argument N of the given function type. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_ARG_(tn, N, ...) \ + tn ::testing::internal::Function<__VA_ARGS__>::Argument##N + +// The matcher type for argument N of the given function type. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_MATCHER_(tn, N, ...) \ + const ::testing::Matcher& + +// The variable for mocking the given method. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_MOCKER_(arity, constness, Method) \ + GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD0_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + ) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 0), \ + this_method_does_not_take_0_arguments); \ + GMOCK_MOCKER_(0, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(0, constness, Method).Invoke(); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method() constness { \ + GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(0, constness, Method).With(); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(0, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD1_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 1), \ + this_method_does_not_take_1_argument); \ + GMOCK_MOCKER_(1, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(1, constness, Method).Invoke(gmock_a1); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1) constness { \ + GMOCK_MOCKER_(1, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(1, constness, Method).With(gmock_a1); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(1, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD2_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 2), \ + this_method_does_not_take_2_arguments); \ + GMOCK_MOCKER_(2, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(2, constness, Method).Invoke(gmock_a1, gmock_a2); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2) constness { \ + GMOCK_MOCKER_(2, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(2, constness, Method).With(gmock_a1, gmock_a2); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(2, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD3_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 3), \ + this_method_does_not_take_3_arguments); \ + GMOCK_MOCKER_(3, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(3, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3) constness { \ + GMOCK_MOCKER_(3, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(3, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(3, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD4_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 4), \ + this_method_does_not_take_4_arguments); \ + GMOCK_MOCKER_(4, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(4, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4) constness { \ + GMOCK_MOCKER_(4, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(4, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(4, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD5_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 5), \ + this_method_does_not_take_5_arguments); \ + GMOCK_MOCKER_(5, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(5, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5) constness { \ + GMOCK_MOCKER_(5, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(5, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(5, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD6_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 6), \ + this_method_does_not_take_6_arguments); \ + GMOCK_MOCKER_(6, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(6, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6) constness { \ + GMOCK_MOCKER_(6, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(6, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(6, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD7_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 7), \ + this_method_does_not_take_7_arguments); \ + GMOCK_MOCKER_(7, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(7, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7) constness { \ + GMOCK_MOCKER_(7, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(7, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(7, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD8_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \ + GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 8), \ + this_method_does_not_take_8_arguments); \ + GMOCK_MOCKER_(8, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(8, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \ + GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8) constness { \ + GMOCK_MOCKER_(8, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(8, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(8, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD9_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \ + GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8, \ + GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 9), \ + this_method_does_not_take_9_arguments); \ + GMOCK_MOCKER_(9, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(9, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \ + gmock_a9); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \ + GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \ + GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9) constness { \ + GMOCK_MOCKER_(9, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(9, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \ + gmock_a9); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(9, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD10_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \ + GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8, \ + GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9, \ + GMOCK_ARG_(tn, 10, __VA_ARGS__) gmock_a10) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 10), \ + this_method_does_not_take_10_arguments); \ + GMOCK_MOCKER_(10, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(10, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ + gmock_a10); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \ + GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \ + GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9, \ + GMOCK_MATCHER_(tn, 10, \ + __VA_ARGS__) gmock_a10) constness { \ + GMOCK_MOCKER_(10, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(10, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ + gmock_a10); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(10, constness, \ + Method) + +#define MOCK_METHOD0(m, ...) GMOCK_METHOD0_(, , , m, __VA_ARGS__) +#define MOCK_METHOD1(m, ...) GMOCK_METHOD1_(, , , m, __VA_ARGS__) +#define MOCK_METHOD2(m, ...) GMOCK_METHOD2_(, , , m, __VA_ARGS__) +#define MOCK_METHOD3(m, ...) GMOCK_METHOD3_(, , , m, __VA_ARGS__) +#define MOCK_METHOD4(m, ...) GMOCK_METHOD4_(, , , m, __VA_ARGS__) +#define MOCK_METHOD5(m, ...) GMOCK_METHOD5_(, , , m, __VA_ARGS__) +#define MOCK_METHOD6(m, ...) GMOCK_METHOD6_(, , , m, __VA_ARGS__) +#define MOCK_METHOD7(m, ...) GMOCK_METHOD7_(, , , m, __VA_ARGS__) +#define MOCK_METHOD8(m, ...) GMOCK_METHOD8_(, , , m, __VA_ARGS__) +#define MOCK_METHOD9(m, ...) GMOCK_METHOD9_(, , , m, __VA_ARGS__) +#define MOCK_METHOD10(m, ...) GMOCK_METHOD10_(, , , m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0(m, ...) GMOCK_METHOD0_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD1(m, ...) GMOCK_METHOD1_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD2(m, ...) GMOCK_METHOD2_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD3(m, ...) GMOCK_METHOD3_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD4(m, ...) GMOCK_METHOD4_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD5(m, ...) GMOCK_METHOD5_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD6(m, ...) GMOCK_METHOD6_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD7(m, ...) GMOCK_METHOD7_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD8(m, ...) GMOCK_METHOD8_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD9(m, ...) GMOCK_METHOD9_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD10(m, ...) GMOCK_METHOD10_(, const, , m, __VA_ARGS__) + +#define MOCK_METHOD0_T(m, ...) GMOCK_METHOD0_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD1_T(m, ...) GMOCK_METHOD1_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD2_T(m, ...) GMOCK_METHOD2_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD3_T(m, ...) GMOCK_METHOD3_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD4_T(m, ...) GMOCK_METHOD4_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD5_T(m, ...) GMOCK_METHOD5_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD6_T(m, ...) GMOCK_METHOD6_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD7_T(m, ...) GMOCK_METHOD7_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD8_T(m, ...) GMOCK_METHOD8_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD9_T(m, ...) GMOCK_METHOD9_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD10_T(m, ...) GMOCK_METHOD10_(typename, , , m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_T(m, ...) \ + GMOCK_METHOD0_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD1_T(m, ...) \ + GMOCK_METHOD1_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD2_T(m, ...) \ + GMOCK_METHOD2_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD3_T(m, ...) \ + GMOCK_METHOD3_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD4_T(m, ...) \ + GMOCK_METHOD4_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD5_T(m, ...) \ + GMOCK_METHOD5_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD6_T(m, ...) \ + GMOCK_METHOD6_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD7_T(m, ...) \ + GMOCK_METHOD7_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD8_T(m, ...) \ + GMOCK_METHOD8_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD9_T(m, ...) \ + GMOCK_METHOD9_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD10_T(m, ...) \ + GMOCK_METHOD10_(typename, const, , m, __VA_ARGS__) + +#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD0_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD1_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD2_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD3_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD4_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD5_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD6_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD7_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD8_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD9_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD10_(, , ct, m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD0_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD1_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD2_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD3_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD4_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD5_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD6_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD7_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD8_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD9_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD10_(, const, ct, m, __VA_ARGS__) + +#define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD0_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD1_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD2_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD3_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD4_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD5_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD6_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD7_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD8_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD9_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD10_(typename, , ct, m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD0_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD1_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD2_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD3_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD4_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD5_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD6_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD7_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD8_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD9_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD10_(typename, const, ct, m, __VA_ARGS__) + +// A MockFunction class has one mock method whose type is F. It is +// useful when you just want your test code to emit some messages and +// have Google Mock verify the right messages are sent (and perhaps at +// the right times). For example, if you are exercising code: +// +// Foo(1); +// Foo(2); +// Foo(3); +// +// and want to verify that Foo(1) and Foo(3) both invoke +// mock.Bar("a"), but Foo(2) doesn't invoke anything, you can write: +// +// TEST(FooTest, InvokesBarCorrectly) { +// MyMock mock; +// MockFunction check; +// { +// InSequence s; +// +// EXPECT_CALL(mock, Bar("a")); +// EXPECT_CALL(check, Call("1")); +// EXPECT_CALL(check, Call("2")); +// EXPECT_CALL(mock, Bar("a")); +// } +// Foo(1); +// check.Call("1"); +// Foo(2); +// check.Call("2"); +// Foo(3); +// } +// +// The expectation spec says that the first Bar("a") must happen +// before check point "1", the second Bar("a") must happen after check +// point "2", and nothing should happen between the two check +// points. The explicit check points make it easy to tell which +// Bar("a") is called by which call to Foo(). +template +class MockFunction; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD0_T(Call, R()); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD1_T(Call, R(A0)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD2_T(Call, R(A0, A1)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD3_T(Call, R(A0, A1, A2)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD4_T(Call, R(A0, A1, A2, A3)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD5_T(Call, R(A0, A1, A2, A3, A4)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD6_T(Call, R(A0, A1, A2, A3, A4, A5)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD7_T(Call, R(A0, A1, A2, A3, A4, A5, A6)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD8_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD9_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD10_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ diff --git a/test/gmock/include/gmock/gmock-generated-function-mockers.h.pump b/test/gmock/include/gmock/gmock-generated-function-mockers.h.pump new file mode 100644 index 0000000..f050caf --- /dev/null +++ b/test/gmock/include/gmock/gmock-generated-function-mockers.h.pump @@ -0,0 +1,265 @@ +$$ -*- mode: c++; -*- +$$ This is a Pump source file. Please use Pump to convert it to +$$ gmock-generated-function-mockers.h. +$$ +$var n = 10 $$ The maximum arity we support. +// 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 implements function mockers of various arities. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ + +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-internal-utils.h" + +namespace testing { +namespace internal { + +template +class FunctionMockerBase; + +// Note: class FunctionMocker really belongs to the ::testing +// namespace. However if we define it in ::testing, MSVC will +// complain when classes in ::testing::internal declare it as a +// friend class template. To workaround this compiler bug, we define +// FunctionMocker in ::testing::internal and import it into ::testing. +template +class FunctionMocker; + + +$range i 0..n +$for i [[ +$range j 1..i +$var typename_As = [[$for j [[, typename A$j]]]] +$var As = [[$for j, [[A$j]]]] +$var as = [[$for j, [[a$j]]]] +$var Aas = [[$for j, [[A$j a$j]]]] +$var ms = [[$for j, [[m$j]]]] +$var matchers = [[$for j, [[const Matcher& m$j]]]] +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F($As); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With($matchers) { + +$if i >= 1 [[ + this->current_spec().SetMatchers(::std::tr1::make_tuple($ms)); + +]] + return this->current_spec(); + } + + R Invoke($Aas) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple($as)); + } +}; + + +]] +} // namespace internal + +// The style guide prohibits "using" statements in a namespace scope +// inside a header file. However, the FunctionMocker class template +// is meant to be defined in the ::testing namespace. The following +// line is just a trick for working around a bug in MSVC 8.0, which +// cannot handle it if we define FunctionMocker in ::testing. +using internal::FunctionMocker; + +// GMOCK_RESULT_(tn, F) expands to the result type of function type F. +// We define this as a variadic macro in case F contains unprotected +// commas (the same reason that we use variadic macros in other places +// in this file). +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_RESULT_(tn, ...) \ + tn ::testing::internal::Function<__VA_ARGS__>::Result + +// The type of argument N of the given function type. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_ARG_(tn, N, ...) \ + tn ::testing::internal::Function<__VA_ARGS__>::Argument##N + +// The matcher type for argument N of the given function type. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_MATCHER_(tn, N, ...) \ + const ::testing::Matcher& + +// The variable for mocking the given method. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_MOCKER_(arity, constness, Method) \ + GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) + + +$for i [[ +$range j 1..i +$var arg_as = [[$for j, \ + [[GMOCK_ARG_(tn, $j, __VA_ARGS__) gmock_a$j]]]] +$var as = [[$for j, [[gmock_a$j]]]] +$var matcher_as = [[$for j, \ + [[GMOCK_MATCHER_(tn, $j, __VA_ARGS__) gmock_a$j]]]] +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD$i[[]]_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + $arg_as) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value == $i), \ + this_method_does_not_take_$i[[]]_argument[[$if i != 1 [[s]]]]); \ + GMOCK_MOCKER_($i, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_($i, constness, Method).Invoke($as); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method($matcher_as) constness { \ + GMOCK_MOCKER_($i, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_($i, constness, Method).With($as); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_($i, constness, Method) + + +]] +$for i [[ +#define MOCK_METHOD$i(m, ...) GMOCK_METHOD$i[[]]_(, , , m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_CONST_METHOD$i(m, ...) GMOCK_METHOD$i[[]]_(, const, , m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_METHOD$i[[]]_T(m, ...) GMOCK_METHOD$i[[]]_(typename, , , m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_CONST_METHOD$i[[]]_T(m, ...) \ + GMOCK_METHOD$i[[]]_(typename, const, , m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_METHOD$i[[]]_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD$i[[]]_(, , ct, m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_CONST_METHOD$i[[]]_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD$i[[]]_(, const, ct, m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD$i[[]]_(typename, , ct, m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_CONST_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD$i[[]]_(typename, const, ct, m, __VA_ARGS__) + +]] + +// A MockFunction class has one mock method whose type is F. It is +// useful when you just want your test code to emit some messages and +// have Google Mock verify the right messages are sent (and perhaps at +// the right times). For example, if you are exercising code: +// +// Foo(1); +// Foo(2); +// Foo(3); +// +// and want to verify that Foo(1) and Foo(3) both invoke +// mock.Bar("a"), but Foo(2) doesn't invoke anything, you can write: +// +// TEST(FooTest, InvokesBarCorrectly) { +// MyMock mock; +// MockFunction check; +// { +// InSequence s; +// +// EXPECT_CALL(mock, Bar("a")); +// EXPECT_CALL(check, Call("1")); +// EXPECT_CALL(check, Call("2")); +// EXPECT_CALL(mock, Bar("a")); +// } +// Foo(1); +// check.Call("1"); +// Foo(2); +// check.Call("2"); +// Foo(3); +// } +// +// The expectation spec says that the first Bar("a") must happen +// before check point "1", the second Bar("a") must happen after check +// point "2", and nothing should happen between the two check +// points. The explicit check points make it easy to tell which +// Bar("a") is called by which call to Foo(). +template +class MockFunction; + + +$for i [[ +$range j 0..i-1 +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD$i[[]]_T(Call, R($for j, [[A$j]])); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + + +]] +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ diff --git a/test/gmock/include/gmock/gmock-generated-matchers.h b/test/gmock/include/gmock/gmock-generated-matchers.h new file mode 100644 index 0000000..b4c8571 --- /dev/null +++ b/test/gmock/include/gmock/gmock-generated-matchers.h @@ -0,0 +1,2190 @@ +// This file was GENERATED by command: +// pump.py gmock-generated-matchers.h.pump +// DO NOT EDIT BY HAND!!! + +// 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 implements some commonly used variadic matchers. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ + +#include +#include +#include +#include +#include "gmock/gmock-matchers.h" + +namespace testing { +namespace internal { + +// The type of the i-th (0-based) field of Tuple. +#define GMOCK_FIELD_TYPE_(Tuple, i) \ + typename ::std::tr1::tuple_element::type + +// TupleFields is for selecting fields from a +// tuple of type Tuple. It has two members: +// +// type: a tuple type whose i-th field is the ki-th field of Tuple. +// GetSelectedFields(t): returns fields k0, ..., and kn of t as a tuple. +// +// For example, in class TupleFields, 2, 0>, we have: +// +// type is tuple, and +// GetSelectedFields(make_tuple(true, 'a', 42)) is (42, true). + +template +class TupleFields; + +// This generic version is used when there are 10 selectors. +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t), get(t), get(t), + get(t), get(t), get(t), get(t), get(t)); + } +}; + +// The following specialization is used for 0 ~ 9 selectors. + +template +class TupleFields { + public: + typedef ::std::tr1::tuple<> type; + static type GetSelectedFields(const Tuple& /* t */) { + using ::std::tr1::get; + return type(); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t), get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t), get(t), get(t), + get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t), get(t), get(t), + get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t), get(t), get(t), + get(t), get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t), get(t), get(t), + get(t), get(t), get(t), get(t)); + } +}; + +#undef GMOCK_FIELD_TYPE_ + +// Implements the Args() matcher. +template +class ArgsMatcherImpl : public MatcherInterface { + public: + // ArgsTuple may have top-level const or reference modifiers. + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple; + typedef typename internal::TupleFields::type SelectedArgs; + typedef Matcher MonomorphicInnerMatcher; + + template + explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) + : inner_matcher_(SafeMatcherCast(inner_matcher)) {} + + virtual bool MatchAndExplain(ArgsTuple args, + MatchResultListener* listener) const { + const SelectedArgs& selected_args = GetSelectedArgs(args); + if (!listener->IsInterested()) + return inner_matcher_.Matches(selected_args); + + PrintIndices(listener->stream()); + *listener << "are " << PrintToString(selected_args); + + StringMatchResultListener inner_listener; + const bool match = inner_matcher_.MatchAndExplain(selected_args, + &inner_listener); + PrintIfNotEmpty(inner_listener.str(), listener->stream()); + return match; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "are a tuple "; + PrintIndices(os); + inner_matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "are a tuple "; + PrintIndices(os); + inner_matcher_.DescribeNegationTo(os); + } + + private: + static SelectedArgs GetSelectedArgs(ArgsTuple args) { + return TupleFields::GetSelectedFields(args); + } + + // Prints the indices of the selected fields. + static void PrintIndices(::std::ostream* os) { + *os << "whose fields ("; + const int indices[10] = { k0, k1, k2, k3, k4, k5, k6, k7, k8, k9 }; + for (int i = 0; i < 10; i++) { + if (indices[i] < 0) + break; + + if (i >= 1) + *os << ", "; + + *os << "#" << indices[i]; + } + *os << ") "; + } + + const MonomorphicInnerMatcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ArgsMatcherImpl); +}; + +template +class ArgsMatcher { + public: + explicit ArgsMatcher(const InnerMatcher& inner_matcher) + : inner_matcher_(inner_matcher) {} + + template + operator Matcher() const { + return MakeMatcher(new ArgsMatcherImpl(inner_matcher_)); + } + + private: + const InnerMatcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ArgsMatcher); +}; + +// A set of metafunctions for computing the result type of AllOf. +// AllOf(m1, ..., mN) returns +// AllOfResultN::type. + +// Although AllOf isn't defined for one argument, AllOfResult1 is defined +// to simplify the implementation. +template +struct AllOfResult1 { + typedef M1 type; +}; + +template +struct AllOfResult2 { + typedef BothOfMatcher< + typename AllOfResult1::type, + typename AllOfResult1::type + > type; +}; + +template +struct AllOfResult3 { + typedef BothOfMatcher< + typename AllOfResult1::type, + typename AllOfResult2::type + > type; +}; + +template +struct AllOfResult4 { + typedef BothOfMatcher< + typename AllOfResult2::type, + typename AllOfResult2::type + > type; +}; + +template +struct AllOfResult5 { + typedef BothOfMatcher< + typename AllOfResult2::type, + typename AllOfResult3::type + > type; +}; + +template +struct AllOfResult6 { + typedef BothOfMatcher< + typename AllOfResult3::type, + typename AllOfResult3::type + > type; +}; + +template +struct AllOfResult7 { + typedef BothOfMatcher< + typename AllOfResult3::type, + typename AllOfResult4::type + > type; +}; + +template +struct AllOfResult8 { + typedef BothOfMatcher< + typename AllOfResult4::type, + typename AllOfResult4::type + > type; +}; + +template +struct AllOfResult9 { + typedef BothOfMatcher< + typename AllOfResult4::type, + typename AllOfResult5::type + > type; +}; + +template +struct AllOfResult10 { + typedef BothOfMatcher< + typename AllOfResult5::type, + typename AllOfResult5::type + > type; +}; + +// A set of metafunctions for computing the result type of AnyOf. +// AnyOf(m1, ..., mN) returns +// AnyOfResultN::type. + +// Although AnyOf isn't defined for one argument, AnyOfResult1 is defined +// to simplify the implementation. +template +struct AnyOfResult1 { + typedef M1 type; +}; + +template +struct AnyOfResult2 { + typedef EitherOfMatcher< + typename AnyOfResult1::type, + typename AnyOfResult1::type + > type; +}; + +template +struct AnyOfResult3 { + typedef EitherOfMatcher< + typename AnyOfResult1::type, + typename AnyOfResult2::type + > type; +}; + +template +struct AnyOfResult4 { + typedef EitherOfMatcher< + typename AnyOfResult2::type, + typename AnyOfResult2::type + > type; +}; + +template +struct AnyOfResult5 { + typedef EitherOfMatcher< + typename AnyOfResult2::type, + typename AnyOfResult3::type + > type; +}; + +template +struct AnyOfResult6 { + typedef EitherOfMatcher< + typename AnyOfResult3::type, + typename AnyOfResult3::type + > type; +}; + +template +struct AnyOfResult7 { + typedef EitherOfMatcher< + typename AnyOfResult3::type, + typename AnyOfResult4::type + > type; +}; + +template +struct AnyOfResult8 { + typedef EitherOfMatcher< + typename AnyOfResult4::type, + typename AnyOfResult4::type + > type; +}; + +template +struct AnyOfResult9 { + typedef EitherOfMatcher< + typename AnyOfResult4::type, + typename AnyOfResult5::type + > type; +}; + +template +struct AnyOfResult10 { + typedef EitherOfMatcher< + typename AnyOfResult5::type, + typename AnyOfResult5::type + > type; +}; + +} // namespace internal + +// Args(a_matcher) matches a tuple if the selected +// fields of it matches a_matcher. C++ doesn't support default +// arguments for function templates, so we have to overload it. +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +// ElementsAre(e_1, e_2, ... e_n) matches an STL-style container with +// n elements, where the i-th element in the container must +// match the i-th argument in the list. Each argument of +// ElementsAre() can be either a value or a matcher. We support up to +// 10 arguments. +// +// The use of DecayArray in the implementation allows ElementsAre() +// to accept string literals, whose type is const char[N], but we +// want to treat them as const char*. +// +// NOTE: Since ElementsAre() cares about the order of the elements, it +// must not be used with containers whose elements's order is +// undefined (e.g. hash_map). + +inline internal::ElementsAreMatcher< + std::tr1::tuple<> > +ElementsAre() { + typedef std::tr1::tuple<> Args; + return internal::ElementsAreMatcher(Args()); +} + +template +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type> > +ElementsAre(const T1& e1) { + typedef std::tr1::tuple< + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1)); +} + +template +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2)); +} + +template +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3)); +} + +template +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4)); +} + +template +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5)); +} + +template +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6)); +} + +template +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7)); +} + +template +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, + e8)); +} + +template +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, + e8, e9)); +} + +template +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9, + const T10& e10) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, + e8, e9, e10)); +} + +// UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension +// that matches n elements in any order. We support up to n=10 arguments. + +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple<> > +UnorderedElementsAre() { + typedef std::tr1::tuple<> Args; + return internal::UnorderedElementsAreMatcher(Args()); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1) { + typedef std::tr1::tuple< + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6, e7)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6, e7, e8)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6, e7, e8, e9)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9, + const T10& e10) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6, e7, e8, e9, e10)); +} + +// AllOf(m1, m2, ..., mk) matches any value that matches all of the given +// sub-matchers. AllOf is called fully qualified to prevent ADL from firing. + +template +inline typename internal::AllOfResult2::type +AllOf(M1 m1, M2 m2) { + return typename internal::AllOfResult2::type( + m1, + m2); +} + +template +inline typename internal::AllOfResult3::type +AllOf(M1 m1, M2 m2, M3 m3) { + return typename internal::AllOfResult3::type( + m1, + ::testing::AllOf(m2, m3)); +} + +template +inline typename internal::AllOfResult4::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4) { + return typename internal::AllOfResult4::type( + ::testing::AllOf(m1, m2), + ::testing::AllOf(m3, m4)); +} + +template +inline typename internal::AllOfResult5::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5) { + return typename internal::AllOfResult5::type( + ::testing::AllOf(m1, m2), + ::testing::AllOf(m3, m4, m5)); +} + +template +inline typename internal::AllOfResult6::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6) { + return typename internal::AllOfResult6::type( + ::testing::AllOf(m1, m2, m3), + ::testing::AllOf(m4, m5, m6)); +} + +template +inline typename internal::AllOfResult7::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7) { + return typename internal::AllOfResult7::type( + ::testing::AllOf(m1, m2, m3), + ::testing::AllOf(m4, m5, m6, m7)); +} + +template +inline typename internal::AllOfResult8::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8) { + return typename internal::AllOfResult8::type( + ::testing::AllOf(m1, m2, m3, m4), + ::testing::AllOf(m5, m6, m7, m8)); +} + +template +inline typename internal::AllOfResult9::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9) { + return typename internal::AllOfResult9::type( + ::testing::AllOf(m1, m2, m3, m4), + ::testing::AllOf(m5, m6, m7, m8, m9)); +} + +template +inline typename internal::AllOfResult10::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) { + return typename internal::AllOfResult10::type( + ::testing::AllOf(m1, m2, m3, m4, m5), + ::testing::AllOf(m6, m7, m8, m9, m10)); +} + +// AnyOf(m1, m2, ..., mk) matches any value that matches any of the given +// sub-matchers. AnyOf is called fully qualified to prevent ADL from firing. + +template +inline typename internal::AnyOfResult2::type +AnyOf(M1 m1, M2 m2) { + return typename internal::AnyOfResult2::type( + m1, + m2); +} + +template +inline typename internal::AnyOfResult3::type +AnyOf(M1 m1, M2 m2, M3 m3) { + return typename internal::AnyOfResult3::type( + m1, + ::testing::AnyOf(m2, m3)); +} + +template +inline typename internal::AnyOfResult4::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4) { + return typename internal::AnyOfResult4::type( + ::testing::AnyOf(m1, m2), + ::testing::AnyOf(m3, m4)); +} + +template +inline typename internal::AnyOfResult5::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5) { + return typename internal::AnyOfResult5::type( + ::testing::AnyOf(m1, m2), + ::testing::AnyOf(m3, m4, m5)); +} + +template +inline typename internal::AnyOfResult6::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6) { + return typename internal::AnyOfResult6::type( + ::testing::AnyOf(m1, m2, m3), + ::testing::AnyOf(m4, m5, m6)); +} + +template +inline typename internal::AnyOfResult7::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7) { + return typename internal::AnyOfResult7::type( + ::testing::AnyOf(m1, m2, m3), + ::testing::AnyOf(m4, m5, m6, m7)); +} + +template +inline typename internal::AnyOfResult8::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8) { + return typename internal::AnyOfResult8::type( + ::testing::AnyOf(m1, m2, m3, m4), + ::testing::AnyOf(m5, m6, m7, m8)); +} + +template +inline typename internal::AnyOfResult9::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9) { + return typename internal::AnyOfResult9::type( + ::testing::AnyOf(m1, m2, m3, m4), + ::testing::AnyOf(m5, m6, m7, m8, m9)); +} + +template +inline typename internal::AnyOfResult10::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) { + return typename internal::AnyOfResult10::type( + ::testing::AnyOf(m1, m2, m3, m4, m5), + ::testing::AnyOf(m6, m7, m8, m9, m10)); +} + +} // namespace testing + + +// The MATCHER* family of macros can be used in a namespace scope to +// define custom matchers easily. +// +// Basic Usage +// =========== +// +// The syntax +// +// MATCHER(name, description_string) { statements; } +// +// defines a matcher with the given name that executes the statements, +// which must return a bool to indicate if the match succeeds. Inside +// the statements, you can refer to the value being matched by 'arg', +// and refer to its type by 'arg_type'. +// +// The description string documents what the matcher does, and is used +// to generate the failure message when the match fails. Since a +// MATCHER() is usually defined in a header file shared by multiple +// C++ source files, we require the description to be a C-string +// literal to avoid possible side effects. It can be empty, in which +// case we'll use the sequence of words in the matcher name as the +// description. +// +// For example: +// +// MATCHER(IsEven, "") { return (arg % 2) == 0; } +// +// allows you to write +// +// // Expects mock_foo.Bar(n) to be called where n is even. +// EXPECT_CALL(mock_foo, Bar(IsEven())); +// +// or, +// +// // Verifies that the value of some_expression is even. +// EXPECT_THAT(some_expression, IsEven()); +// +// If the above assertion fails, it will print something like: +// +// Value of: some_expression +// Expected: is even +// Actual: 7 +// +// where the description "is even" is automatically calculated from the +// matcher name IsEven. +// +// Argument Type +// ============= +// +// Note that the type of the value being matched (arg_type) is +// determined by the context in which you use the matcher and is +// supplied to you by the compiler, so you don't need to worry about +// declaring it (nor can you). This allows the matcher to be +// polymorphic. For example, IsEven() can be used to match any type +// where the value of "(arg % 2) == 0" can be implicitly converted to +// a bool. In the "Bar(IsEven())" example above, if method Bar() +// takes an int, 'arg_type' will be int; if it takes an unsigned long, +// 'arg_type' will be unsigned long; and so on. +// +// Parameterizing Matchers +// ======================= +// +// Sometimes you'll want to parameterize the matcher. For that you +// can use another macro: +// +// MATCHER_P(name, param_name, description_string) { statements; } +// +// For example: +// +// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } +// +// will allow you to write: +// +// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); +// +// which may lead to this message (assuming n is 10): +// +// Value of: Blah("a") +// Expected: has absolute value 10 +// Actual: -9 +// +// Note that both the matcher description and its parameter are +// printed, making the message human-friendly. +// +// In the matcher definition body, you can write 'foo_type' to +// reference the type of a parameter named 'foo'. For example, in the +// body of MATCHER_P(HasAbsoluteValue, value) above, you can write +// 'value_type' to refer to the type of 'value'. +// +// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P10 to +// support multi-parameter matchers. +// +// Describing Parameterized Matchers +// ================================= +// +// The last argument to MATCHER*() is a string-typed expression. The +// expression can reference all of the matcher's parameters and a +// special bool-typed variable named 'negation'. When 'negation' is +// false, the expression should evaluate to the matcher's description; +// otherwise it should evaluate to the description of the negation of +// the matcher. For example, +// +// using testing::PrintToString; +// +// MATCHER_P2(InClosedRange, low, hi, +// string(negation ? "is not" : "is") + " in range [" + +// PrintToString(low) + ", " + PrintToString(hi) + "]") { +// return low <= arg && arg <= hi; +// } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: is in range [4, 6] +// ... +// Expected: is not in range [2, 4] +// +// If you specify "" as the description, the failure message will +// contain the sequence of words in the matcher name followed by the +// parameter values printed as a tuple. For example, +// +// MATCHER_P2(InClosedRange, low, hi, "") { ... } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: in closed range (4, 6) +// ... +// Expected: not (in closed range (2, 4)) +// +// Types of Matcher Parameters +// =========================== +// +// For the purpose of typing, you can view +// +// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } +// +// as shorthand for +// +// template +// FooMatcherPk +// Foo(p1_type p1, ..., pk_type pk) { ... } +// +// When you write Foo(v1, ..., vk), the compiler infers the types of +// the parameters v1, ..., and vk for you. If you are not happy with +// the result of the type inference, you can specify the types by +// explicitly instantiating the template, as in Foo(5, +// false). As said earlier, you don't get to (or need to) specify +// 'arg_type' as that's determined by the context in which the matcher +// is used. You can assign the result of expression Foo(p1, ..., pk) +// to a variable of type FooMatcherPk. This +// can be useful when composing matchers. +// +// While you can instantiate a matcher template with reference types, +// passing the parameters by pointer usually makes your code more +// readable. If, however, you still want to pass a parameter by +// reference, be aware that in the failure message generated by the +// matcher you will see the value of the referenced object but not its +// address. +// +// Explaining Match Results +// ======================== +// +// Sometimes the matcher description alone isn't enough to explain why +// the match has failed or succeeded. For example, when expecting a +// long string, it can be very helpful to also print the diff between +// the expected string and the actual one. To achieve that, you can +// optionally stream additional information to a special variable +// named result_listener, whose type is a pointer to class +// MatchResultListener: +// +// MATCHER_P(EqualsLongString, str, "") { +// if (arg == str) return true; +// +// *result_listener << "the difference: " +/// << DiffStrings(str, arg); +// return false; +// } +// +// Overloading Matchers +// ==================== +// +// You can overload matchers with different numbers of parameters: +// +// MATCHER_P(Blah, a, description_string1) { ... } +// MATCHER_P2(Blah, a, b, description_string2) { ... } +// +// Caveats +// ======= +// +// When defining a new matcher, you should also consider implementing +// MatcherInterface or using MakePolymorphicMatcher(). These +// approaches require more work than the MATCHER* macros, but also +// give you more control on the types of the value being matched and +// the matcher parameters, which may leads to better compiler error +// messages when the matcher is used wrong. They also allow +// overloading matchers based on parameter types (as opposed to just +// based on the number of parameters). +// +// MATCHER*() can only be used in a namespace scope. The reason is +// that C++ doesn't yet allow function-local types to be used to +// instantiate templates. The up-coming C++0x standard will fix this. +// Once that's done, we'll consider supporting using MATCHER*() inside +// a function. +// +// More Information +// ================ +// +// To learn more about using these macros, please search for 'MATCHER' +// on http://code.google.com/p/googlemock/wiki/CookBook. + +#define MATCHER(name, description)\ + class name##Matcher {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl()\ + {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple<>()));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl());\ + }\ + name##Matcher() {\ + }\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##Matcher);\ + };\ + inline name##Matcher name() {\ + return name##Matcher();\ + }\ + template \ + bool name##Matcher::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P(name, p0, description)\ + template \ + class name##MatcherP {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + explicit gmock_Impl(p0##_type gmock_p0)\ + : p0(gmock_p0) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0));\ + }\ + name##MatcherP(p0##_type gmock_p0) : p0(gmock_p0) {\ + }\ + p0##_type p0;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP);\ + };\ + template \ + inline name##MatcherP name(p0##_type p0) {\ + return name##MatcherP(p0);\ + }\ + template \ + template \ + bool name##MatcherP::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P2(name, p0, p1, description)\ + template \ + class name##MatcherP2 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1)\ + : p0(gmock_p0), p1(gmock_p1) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1));\ + }\ + name##MatcherP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ + p1(gmock_p1) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP2);\ + };\ + template \ + inline name##MatcherP2 name(p0##_type p0, \ + p1##_type p1) {\ + return name##MatcherP2(p0, p1);\ + }\ + template \ + template \ + bool name##MatcherP2::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P3(name, p0, p1, p2, description)\ + template \ + class name##MatcherP3 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1, \ + p2)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2));\ + }\ + name##MatcherP3(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP3);\ + };\ + template \ + inline name##MatcherP3 name(p0##_type p0, \ + p1##_type p1, p2##_type p2) {\ + return name##MatcherP3(p0, p1, p2);\ + }\ + template \ + template \ + bool name##MatcherP3::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P4(name, p0, p1, p2, p3, description)\ + template \ + class name##MatcherP4 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1, p2, p3)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3));\ + }\ + name##MatcherP4(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP4);\ + };\ + template \ + inline name##MatcherP4 name(p0##_type p0, p1##_type p1, p2##_type p2, \ + p3##_type p3) {\ + return name##MatcherP4(p0, \ + p1, p2, p3);\ + }\ + template \ + template \ + bool name##MatcherP4::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P5(name, p0, p1, p2, p3, p4, description)\ + template \ + class name##MatcherP5 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1, p2, p3, p4)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4));\ + }\ + name##MatcherP5(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, \ + p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP5);\ + };\ + template \ + inline name##MatcherP5 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4) {\ + return name##MatcherP5(p0, p1, p2, p3, p4);\ + }\ + template \ + template \ + bool name##MatcherP5::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P6(name, p0, p1, p2, p3, p4, p5, description)\ + template \ + class name##MatcherP6 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4), p5(gmock_p5) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1, p2, p3, p4, p5)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5));\ + }\ + name##MatcherP6(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP6);\ + };\ + template \ + inline name##MatcherP6 name(p0##_type p0, p1##_type p1, p2##_type p2, \ + p3##_type p3, p4##_type p4, p5##_type p5) {\ + return name##MatcherP6(p0, p1, p2, p3, p4, p5);\ + }\ + template \ + template \ + bool name##MatcherP6::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P7(name, p0, p1, p2, p3, p4, p5, p6, description)\ + template \ + class name##MatcherP7 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1, p2, p3, p4, p5, \ + p6)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5, p6));\ + }\ + name##MatcherP7(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), \ + p6(gmock_p6) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP7);\ + };\ + template \ + inline name##MatcherP7 name(p0##_type p0, p1##_type p1, \ + p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ + p6##_type p6) {\ + return name##MatcherP7(p0, p1, p2, p3, p4, p5, p6);\ + }\ + template \ + template \ + bool name##MatcherP7::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P8(name, p0, p1, p2, p3, p4, p5, p6, p7, description)\ + template \ + class name##MatcherP8 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1, p2, \ + p3, p4, p5, p6, p7)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7));\ + }\ + name##MatcherP8(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, \ + p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP8);\ + };\ + template \ + inline name##MatcherP8 name(p0##_type p0, \ + p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ + p6##_type p6, p7##_type p7) {\ + return name##MatcherP8(p0, p1, p2, p3, p4, p5, \ + p6, p7);\ + }\ + template \ + template \ + bool name##MatcherP8::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, description)\ + template \ + class name##MatcherP9 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ + p8(gmock_p8) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1, p2, p3, p4, p5, p6, p7, p8)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7, p8));\ + }\ + name##MatcherP9(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ + p8(gmock_p8) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP9);\ + };\ + template \ + inline name##MatcherP9 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, \ + p8##_type p8) {\ + return name##MatcherP9(p0, p1, p2, \ + p3, p4, p5, p6, p7, p8);\ + }\ + template \ + template \ + bool name##MatcherP9::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, description)\ + template \ + class name##MatcherP10 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \ + p9##_type gmock_p9)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ + p8(gmock_p8), p9(gmock_p9) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + p9##_type p9;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9));\ + }\ + name##MatcherP10(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8, p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + p9##_type p9;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP10);\ + };\ + template \ + inline name##MatcherP10 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \ + p9##_type p9) {\ + return name##MatcherP10(p0, \ + p1, p2, p3, p4, p5, p6, p7, p8, p9);\ + }\ + template \ + template \ + bool name##MatcherP10::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/test/gmock/include/gmock/gmock-generated-matchers.h.pump b/test/gmock/include/gmock/gmock-generated-matchers.h.pump new file mode 100644 index 0000000..af02acb --- /dev/null +++ b/test/gmock/include/gmock/gmock-generated-matchers.h.pump @@ -0,0 +1,674 @@ +$$ -*- 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 line fixes auto-indentation of the following code in Emacs. +// 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 implements some commonly used variadic matchers. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ + +#include +#include +#include +#include +#include "gmock/gmock-matchers.h" + +namespace testing { +namespace internal { + +$range i 0..n-1 + +// The type of the i-th (0-based) field of Tuple. +#define GMOCK_FIELD_TYPE_(Tuple, i) \ + typename ::std::tr1::tuple_element::type + +// TupleFields is for selecting fields from a +// tuple of type Tuple. It has two members: +// +// type: a tuple type whose i-th field is the ki-th field of Tuple. +// GetSelectedFields(t): returns fields k0, ..., and kn of t as a tuple. +// +// For example, in class TupleFields, 2, 0>, we have: +// +// type is tuple, and +// GetSelectedFields(make_tuple(true, 'a', 42)) is (42, true). + +template +class TupleFields; + +// This generic version is used when there are $n selectors. +template +class TupleFields { + public: + typedef ::std::tr1::tuple<$for i, [[GMOCK_FIELD_TYPE_(Tuple, k$i)]]> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type($for i, [[get(t)]]); + } +}; + +// The following specialization is used for 0 ~ $(n-1) selectors. + +$for i [[ +$$ }}} +$range j 0..i-1 +$range k 0..n-1 + +template +class TupleFields { + public: + typedef ::std::tr1::tuple<$for j, [[GMOCK_FIELD_TYPE_(Tuple, k$j)]]> type; + static type GetSelectedFields(const Tuple& $if i==0 [[/* t */]] $else [[t]]) { + using ::std::tr1::get; + return type($for j, [[get(t)]]); + } +}; + +]] + +#undef GMOCK_FIELD_TYPE_ + +// Implements the Args() matcher. + +$var ks = [[$for i, [[k$i]]]] +template +class ArgsMatcherImpl : public MatcherInterface { + public: + // ArgsTuple may have top-level const or reference modifiers. + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple; + typedef typename internal::TupleFields::type SelectedArgs; + typedef Matcher MonomorphicInnerMatcher; + + template + explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) + : inner_matcher_(SafeMatcherCast(inner_matcher)) {} + + virtual bool MatchAndExplain(ArgsTuple args, + MatchResultListener* listener) const { + const SelectedArgs& selected_args = GetSelectedArgs(args); + if (!listener->IsInterested()) + return inner_matcher_.Matches(selected_args); + + PrintIndices(listener->stream()); + *listener << "are " << PrintToString(selected_args); + + StringMatchResultListener inner_listener; + const bool match = inner_matcher_.MatchAndExplain(selected_args, + &inner_listener); + PrintIfNotEmpty(inner_listener.str(), listener->stream()); + return match; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "are a tuple "; + PrintIndices(os); + inner_matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "are a tuple "; + PrintIndices(os); + inner_matcher_.DescribeNegationTo(os); + } + + private: + static SelectedArgs GetSelectedArgs(ArgsTuple args) { + return TupleFields::GetSelectedFields(args); + } + + // Prints the indices of the selected fields. + static void PrintIndices(::std::ostream* os) { + *os << "whose fields ("; + const int indices[$n] = { $ks }; + for (int i = 0; i < $n; i++) { + if (indices[i] < 0) + break; + + if (i >= 1) + *os << ", "; + + *os << "#" << indices[i]; + } + *os << ") "; + } + + const MonomorphicInnerMatcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ArgsMatcherImpl); +}; + +template +class ArgsMatcher { + public: + explicit ArgsMatcher(const InnerMatcher& inner_matcher) + : inner_matcher_(inner_matcher) {} + + template + operator Matcher() const { + return MakeMatcher(new ArgsMatcherImpl(inner_matcher_)); + } + + private: + const InnerMatcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ArgsMatcher); +}; + +// A set of metafunctions for computing the result type of AllOf. +// AllOf(m1, ..., mN) returns +// AllOfResultN::type. + +// Although AllOf isn't defined for one argument, AllOfResult1 is defined +// to simplify the implementation. +template +struct AllOfResult1 { + typedef M1 type; +}; + +$range i 1..n + +$range i 2..n +$for i [[ +$range j 2..i +$var m = i/2 +$range k 1..m +$range t m+1..i + +template +struct AllOfResult$i { + typedef BothOfMatcher< + typename AllOfResult$m<$for k, [[M$k]]>::type, + typename AllOfResult$(i-m)<$for t, [[M$t]]>::type + > type; +}; + +]] + +// A set of metafunctions for computing the result type of AnyOf. +// AnyOf(m1, ..., mN) returns +// AnyOfResultN::type. + +// Although AnyOf isn't defined for one argument, AnyOfResult1 is defined +// to simplify the implementation. +template +struct AnyOfResult1 { + typedef M1 type; +}; + +$range i 1..n + +$range i 2..n +$for i [[ +$range j 2..i +$var m = i/2 +$range k 1..m +$range t m+1..i + +template +struct AnyOfResult$i { + typedef EitherOfMatcher< + typename AnyOfResult$m<$for k, [[M$k]]>::type, + typename AnyOfResult$(i-m)<$for t, [[M$t]]>::type + > type; +}; + +]] + +} // namespace internal + +// Args(a_matcher) matches a tuple if the selected +// fields of it matches a_matcher. C++ doesn't support default +// arguments for function templates, so we have to overload it. + +$range i 0..n +$for i [[ +$range j 1..i +template <$for j [[int k$j, ]]typename InnerMatcher> +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + + +]] +// ElementsAre(e_1, e_2, ... e_n) matches an STL-style container with +// n elements, where the i-th element in the container must +// match the i-th argument in the list. Each argument of +// ElementsAre() can be either a value or a matcher. We support up to +// $n arguments. +// +// The use of DecayArray in the implementation allows ElementsAre() +// to accept string literals, whose type is const char[N], but we +// want to treat them as const char*. +// +// NOTE: Since ElementsAre() cares about the order of the elements, it +// must not be used with containers whose elements's order is +// undefined (e.g. hash_map). + +$range i 0..n +$for i [[ + +$range j 1..i + +$if i>0 [[ + +template <$for j, [[typename T$j]]> +]] + +inline internal::ElementsAreMatcher< + std::tr1::tuple< +$for j, [[ + + typename internal::DecayArray::type]]> > +ElementsAre($for j, [[const T$j& e$j]]) { + typedef std::tr1::tuple< +$for j, [[ + + typename internal::DecayArray::type]]> Args; + return internal::ElementsAreMatcher(Args($for j, [[e$j]])); +} + +]] + +// UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension +// that matches n elements in any order. We support up to n=$n arguments. + +$range i 0..n +$for i [[ + +$range j 1..i + +$if i>0 [[ + +template <$for j, [[typename T$j]]> +]] + +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< +$for j, [[ + + typename internal::DecayArray::type]]> > +UnorderedElementsAre($for j, [[const T$j& e$j]]) { + typedef std::tr1::tuple< +$for j, [[ + + typename internal::DecayArray::type]]> Args; + return internal::UnorderedElementsAreMatcher(Args($for j, [[e$j]])); +} + +]] + +// AllOf(m1, m2, ..., mk) matches any value that matches all of the given +// sub-matchers. AllOf is called fully qualified to prevent ADL from firing. + +$range i 2..n +$for i [[ +$range j 1..i +$var m = i/2 +$range k 1..m +$range t m+1..i + +template <$for j, [[typename M$j]]> +inline typename internal::AllOfResult$i<$for j, [[M$j]]>::type +AllOf($for j, [[M$j m$j]]) { + return typename internal::AllOfResult$i<$for j, [[M$j]]>::type( + $if m == 1 [[m1]] $else [[::testing::AllOf($for k, [[m$k]])]], + $if m+1 == i [[m$i]] $else [[::testing::AllOf($for t, [[m$t]])]]); +} + +]] + +// AnyOf(m1, m2, ..., mk) matches any value that matches any of the given +// sub-matchers. AnyOf is called fully qualified to prevent ADL from firing. + +$range i 2..n +$for i [[ +$range j 1..i +$var m = i/2 +$range k 1..m +$range t m+1..i + +template <$for j, [[typename M$j]]> +inline typename internal::AnyOfResult$i<$for j, [[M$j]]>::type +AnyOf($for j, [[M$j m$j]]) { + return typename internal::AnyOfResult$i<$for j, [[M$j]]>::type( + $if m == 1 [[m1]] $else [[::testing::AnyOf($for k, [[m$k]])]], + $if m+1 == i [[m$i]] $else [[::testing::AnyOf($for t, [[m$t]])]]); +} + +]] + +} // namespace testing +$$ } // This Pump meta comment fixes auto-indentation in Emacs. It will not +$$ // show up in the generated code. + + +// The MATCHER* family of macros can be used in a namespace scope to +// define custom matchers easily. +// +// Basic Usage +// =========== +// +// The syntax +// +// MATCHER(name, description_string) { statements; } +// +// defines a matcher with the given name that executes the statements, +// which must return a bool to indicate if the match succeeds. Inside +// the statements, you can refer to the value being matched by 'arg', +// and refer to its type by 'arg_type'. +// +// The description string documents what the matcher does, and is used +// to generate the failure message when the match fails. Since a +// MATCHER() is usually defined in a header file shared by multiple +// C++ source files, we require the description to be a C-string +// literal to avoid possible side effects. It can be empty, in which +// case we'll use the sequence of words in the matcher name as the +// description. +// +// For example: +// +// MATCHER(IsEven, "") { return (arg % 2) == 0; } +// +// allows you to write +// +// // Expects mock_foo.Bar(n) to be called where n is even. +// EXPECT_CALL(mock_foo, Bar(IsEven())); +// +// or, +// +// // Verifies that the value of some_expression is even. +// EXPECT_THAT(some_expression, IsEven()); +// +// If the above assertion fails, it will print something like: +// +// Value of: some_expression +// Expected: is even +// Actual: 7 +// +// where the description "is even" is automatically calculated from the +// matcher name IsEven. +// +// Argument Type +// ============= +// +// Note that the type of the value being matched (arg_type) is +// determined by the context in which you use the matcher and is +// supplied to you by the compiler, so you don't need to worry about +// declaring it (nor can you). This allows the matcher to be +// polymorphic. For example, IsEven() can be used to match any type +// where the value of "(arg % 2) == 0" can be implicitly converted to +// a bool. In the "Bar(IsEven())" example above, if method Bar() +// takes an int, 'arg_type' will be int; if it takes an unsigned long, +// 'arg_type' will be unsigned long; and so on. +// +// Parameterizing Matchers +// ======================= +// +// Sometimes you'll want to parameterize the matcher. For that you +// can use another macro: +// +// MATCHER_P(name, param_name, description_string) { statements; } +// +// For example: +// +// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } +// +// will allow you to write: +// +// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); +// +// which may lead to this message (assuming n is 10): +// +// Value of: Blah("a") +// Expected: has absolute value 10 +// Actual: -9 +// +// Note that both the matcher description and its parameter are +// printed, making the message human-friendly. +// +// In the matcher definition body, you can write 'foo_type' to +// reference the type of a parameter named 'foo'. For example, in the +// body of MATCHER_P(HasAbsoluteValue, value) above, you can write +// 'value_type' to refer to the type of 'value'. +// +// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to +// support multi-parameter matchers. +// +// Describing Parameterized Matchers +// ================================= +// +// The last argument to MATCHER*() is a string-typed expression. The +// expression can reference all of the matcher's parameters and a +// special bool-typed variable named 'negation'. When 'negation' is +// false, the expression should evaluate to the matcher's description; +// otherwise it should evaluate to the description of the negation of +// the matcher. For example, +// +// using testing::PrintToString; +// +// MATCHER_P2(InClosedRange, low, hi, +// string(negation ? "is not" : "is") + " in range [" + +// PrintToString(low) + ", " + PrintToString(hi) + "]") { +// return low <= arg && arg <= hi; +// } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: is in range [4, 6] +// ... +// Expected: is not in range [2, 4] +// +// If you specify "" as the description, the failure message will +// contain the sequence of words in the matcher name followed by the +// parameter values printed as a tuple. For example, +// +// MATCHER_P2(InClosedRange, low, hi, "") { ... } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: in closed range (4, 6) +// ... +// Expected: not (in closed range (2, 4)) +// +// Types of Matcher Parameters +// =========================== +// +// For the purpose of typing, you can view +// +// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } +// +// as shorthand for +// +// template +// FooMatcherPk +// Foo(p1_type p1, ..., pk_type pk) { ... } +// +// When you write Foo(v1, ..., vk), the compiler infers the types of +// the parameters v1, ..., and vk for you. If you are not happy with +// the result of the type inference, you can specify the types by +// explicitly instantiating the template, as in Foo(5, +// false). As said earlier, you don't get to (or need to) specify +// 'arg_type' as that's determined by the context in which the matcher +// is used. You can assign the result of expression Foo(p1, ..., pk) +// to a variable of type FooMatcherPk. This +// can be useful when composing matchers. +// +// While you can instantiate a matcher template with reference types, +// passing the parameters by pointer usually makes your code more +// readable. If, however, you still want to pass a parameter by +// reference, be aware that in the failure message generated by the +// matcher you will see the value of the referenced object but not its +// address. +// +// Explaining Match Results +// ======================== +// +// Sometimes the matcher description alone isn't enough to explain why +// the match has failed or succeeded. For example, when expecting a +// long string, it can be very helpful to also print the diff between +// the expected string and the actual one. To achieve that, you can +// optionally stream additional information to a special variable +// named result_listener, whose type is a pointer to class +// MatchResultListener: +// +// MATCHER_P(EqualsLongString, str, "") { +// if (arg == str) return true; +// +// *result_listener << "the difference: " +/// << DiffStrings(str, arg); +// return false; +// } +// +// Overloading Matchers +// ==================== +// +// You can overload matchers with different numbers of parameters: +// +// MATCHER_P(Blah, a, description_string1) { ... } +// MATCHER_P2(Blah, a, b, description_string2) { ... } +// +// Caveats +// ======= +// +// When defining a new matcher, you should also consider implementing +// MatcherInterface or using MakePolymorphicMatcher(). These +// approaches require more work than the MATCHER* macros, but also +// give you more control on the types of the value being matched and +// the matcher parameters, which may leads to better compiler error +// messages when the matcher is used wrong. They also allow +// overloading matchers based on parameter types (as opposed to just +// based on the number of parameters). +// +// MATCHER*() can only be used in a namespace scope. The reason is +// that C++ doesn't yet allow function-local types to be used to +// instantiate templates. The up-coming C++0x standard will fix this. +// Once that's done, we'll consider supporting using MATCHER*() inside +// a function. +// +// More Information +// ================ +// +// To learn more about using these macros, please search for 'MATCHER' +// on http://code.google.com/p/googlemock/wiki/CookBook. + +$range i 0..n +$for i + +[[ +$var macro_name = [[$if i==0 [[MATCHER]] $elif i==1 [[MATCHER_P]] + $else [[MATCHER_P$i]]]] +$var class_name = [[name##Matcher[[$if i==0 [[]] $elif i==1 [[P]] + $else [[P$i]]]]]] +$range j 0..i-1 +$var template = [[$if i==0 [[]] $else [[ + + template <$for j, [[typename p$j##_type]]>\ +]]]] +$var ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]] +$var impl_ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]] +$var impl_inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] +$var inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] +$var params = [[$for j, [[p$j]]]] +$var param_types = [[$if i==0 [[]] $else [[<$for j, [[p$j##_type]]>]]]] +$var param_types_and_names = [[$for j, [[p$j##_type p$j]]]] +$var param_field_decls = [[$for j +[[ + + p$j##_type p$j;\ +]]]] +$var param_field_decls2 = [[$for j +[[ + + p$j##_type p$j;\ +]]]] + +#define $macro_name(name$for j [[, p$j]], description)\$template + class $class_name {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + [[$if i==1 [[explicit ]]]]gmock_Impl($impl_ctor_param_list)\ + $impl_inits {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\$param_field_decls + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple<$for j, [[p$j##_type]]>($for j, [[p$j]])));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl($params));\ + }\ + $class_name($ctor_param_list)$inits {\ + }\$param_field_decls2 + private:\ + GTEST_DISALLOW_ASSIGN_($class_name);\ + };\$template + inline $class_name$param_types name($param_types_and_names) {\ + return $class_name$param_types($params);\ + }\$template + template \ + bool $class_name$param_types::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const +]] + + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/test/gmock/include/gmock/gmock-generated-nice-strict.h b/test/gmock/include/gmock/gmock-generated-nice-strict.h new file mode 100644 index 0000000..4095f4d --- /dev/null +++ b/test/gmock/include/gmock/gmock-generated-nice-strict.h @@ -0,0 +1,397 @@ +// This file was GENERATED by command: +// pump.py gmock-generated-nice-strict.h.pump +// DO NOT EDIT BY HAND!!! + +// 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. +// +// Author: wan@google.com (Zhanyong Wan) + +// Implements class templates NiceMock, NaggyMock, and StrictMock. +// +// Given a mock class MockFoo that is created using Google Mock, +// NiceMock is a subclass of MockFoo that allows +// uninteresting calls (i.e. calls to mock methods that have no +// EXPECT_CALL specs), NaggyMock is a subclass of MockFoo +// that prints a warning when an uninteresting call occurs, and +// StrictMock is a subclass of MockFoo that treats all +// uninteresting calls as errors. +// +// Currently a mock is naggy by default, so MockFoo and +// NaggyMock behave like the same. However, we will soon +// switch the default behavior of mocks to be nice, as that in general +// leads to more maintainable tests. When that happens, MockFoo will +// stop behaving like NaggyMock and start behaving like +// NiceMock. +// +// NiceMock, NaggyMock, and StrictMock "inherit" the constructors of +// their respective base class, with up-to 10 arguments. Therefore +// you can write NiceMock(5, "a") to construct a nice mock +// where MockFoo has a constructor that accepts (int, const char*), +// for example. +// +// A known limitation is that NiceMock, NaggyMock, +// and StrictMock only works for mock methods defined using +// the MOCK_METHOD* family of macros DIRECTLY in the MockFoo class. +// If a mock method is defined in a base class of MockFoo, the "nice" +// or "strict" modifier may not affect it, depending on the compiler. +// In particular, nesting NiceMock, NaggyMock, and StrictMock is NOT +// supported. +// +// Another known limitation is that the constructors of the base mock +// cannot have arguments passed by non-const reference, which are +// banned by the Google C++ style guide anyway. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ + +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-port.h" + +namespace testing { + +template +class NiceMock : public MockClass { + public: + // We don't factor out the constructor body to a common method, as + // we have to avoid a possible clash with members of MockClass. + NiceMock() { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + // C++ doesn't (yet) allow inheritance of constructors, so we have + // to define it for each arity. + template + explicit NiceMock(const A1& a1) : MockClass(a1) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + template + NiceMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, + const A4& a4) : MockClass(a1, a2, a3, a4) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5) : MockClass(a1, a2, a3, a4, a5) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5, + a6, a7) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1, + a2, a3, a4, a5, a6, a7, a8) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8, + const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, + const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + virtual ~NiceMock() { + ::testing::Mock::UnregisterCallReaction( + internal::ImplicitCast_(this)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(NiceMock); +}; + +template +class NaggyMock : public MockClass { + public: + // We don't factor out the constructor body to a common method, as + // we have to avoid a possible clash with members of MockClass. + NaggyMock() { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + // C++ doesn't (yet) allow inheritance of constructors, so we have + // to define it for each arity. + template + explicit NaggyMock(const A1& a1) : MockClass(a1) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + template + NaggyMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, + const A4& a4) : MockClass(a1, a2, a3, a4) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5) : MockClass(a1, a2, a3, a4, a5) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5, + a6, a7) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1, + a2, a3, a4, a5, a6, a7, a8) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8, + const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, + const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + virtual ~NaggyMock() { + ::testing::Mock::UnregisterCallReaction( + internal::ImplicitCast_(this)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(NaggyMock); +}; + +template +class StrictMock : public MockClass { + public: + // We don't factor out the constructor body to a common method, as + // we have to avoid a possible clash with members of MockClass. + StrictMock() { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + // C++ doesn't (yet) allow inheritance of constructors, so we have + // to define it for each arity. + template + explicit StrictMock(const A1& a1) : MockClass(a1) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + template + StrictMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, + const A4& a4) : MockClass(a1, a2, a3, a4) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5) : MockClass(a1, a2, a3, a4, a5) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5, + a6, a7) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1, + a2, a3, a4, a5, a6, a7, a8) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8, + const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, + const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + virtual ~StrictMock() { + ::testing::Mock::UnregisterCallReaction( + internal::ImplicitCast_(this)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StrictMock); +}; + +// The following specializations catch some (relatively more common) +// user errors of nesting nice and strict mocks. They do NOT catch +// all possible errors. + +// These specializations are declared but not defined, as NiceMock, +// NaggyMock, and StrictMock cannot be nested. + +template +class NiceMock >; +template +class NiceMock >; +template +class NiceMock >; + +template +class NaggyMock >; +template +class NaggyMock >; +template +class NaggyMock >; + +template +class StrictMock >; +template +class StrictMock >; +template +class StrictMock >; + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ diff --git a/test/gmock/include/gmock/gmock-generated-nice-strict.h.pump b/test/gmock/include/gmock/gmock-generated-nice-strict.h.pump new file mode 100644 index 0000000..3ee1ce7 --- /dev/null +++ b/test/gmock/include/gmock/gmock-generated-nice-strict.h.pump @@ -0,0 +1,161 @@ +$$ -*- mode: c++; -*- +$$ This is a Pump source file. Please use Pump to convert it to +$$ gmock-generated-nice-strict.h. +$$ +$var n = 10 $$ The maximum arity we support. +// 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. +// +// Author: wan@google.com (Zhanyong Wan) + +// Implements class templates NiceMock, NaggyMock, and StrictMock. +// +// Given a mock class MockFoo that is created using Google Mock, +// NiceMock is a subclass of MockFoo that allows +// uninteresting calls (i.e. calls to mock methods that have no +// EXPECT_CALL specs), NaggyMock is a subclass of MockFoo +// that prints a warning when an uninteresting call occurs, and +// StrictMock is a subclass of MockFoo that treats all +// uninteresting calls as errors. +// +// Currently a mock is naggy by default, so MockFoo and +// NaggyMock behave like the same. However, we will soon +// switch the default behavior of mocks to be nice, as that in general +// leads to more maintainable tests. When that happens, MockFoo will +// stop behaving like NaggyMock and start behaving like +// NiceMock. +// +// NiceMock, NaggyMock, and StrictMock "inherit" the constructors of +// their respective base class, with up-to $n arguments. Therefore +// you can write NiceMock(5, "a") to construct a nice mock +// where MockFoo has a constructor that accepts (int, const char*), +// for example. +// +// A known limitation is that NiceMock, NaggyMock, +// and StrictMock only works for mock methods defined using +// the MOCK_METHOD* family of macros DIRECTLY in the MockFoo class. +// If a mock method is defined in a base class of MockFoo, the "nice" +// or "strict" modifier may not affect it, depending on the compiler. +// In particular, nesting NiceMock, NaggyMock, and StrictMock is NOT +// supported. +// +// Another known limitation is that the constructors of the base mock +// cannot have arguments passed by non-const reference, which are +// banned by the Google C++ style guide anyway. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ + +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-port.h" + +namespace testing { + +$range kind 0..2 +$for kind [[ + +$var clazz=[[$if kind==0 [[NiceMock]] + $elif kind==1 [[NaggyMock]] + $else [[StrictMock]]]] + +$var method=[[$if kind==0 [[AllowUninterestingCalls]] + $elif kind==1 [[WarnUninterestingCalls]] + $else [[FailUninterestingCalls]]]] + +template +class $clazz : public MockClass { + public: + // We don't factor out the constructor body to a common method, as + // we have to avoid a possible clash with members of MockClass. + $clazz() { + ::testing::Mock::$method( + internal::ImplicitCast_(this)); + } + + // C++ doesn't (yet) allow inheritance of constructors, so we have + // to define it for each arity. + template + explicit $clazz(const A1& a1) : MockClass(a1) { + ::testing::Mock::$method( + internal::ImplicitCast_(this)); + } + +$range i 2..n +$for i [[ +$range j 1..i + template <$for j, [[typename A$j]]> + $clazz($for j, [[const A$j& a$j]]) : MockClass($for j, [[a$j]]) { + ::testing::Mock::$method( + internal::ImplicitCast_(this)); + } + + +]] + virtual ~$clazz() { + ::testing::Mock::UnregisterCallReaction( + internal::ImplicitCast_(this)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_($clazz); +}; + +]] + +// The following specializations catch some (relatively more common) +// user errors of nesting nice and strict mocks. They do NOT catch +// all possible errors. + +// These specializations are declared but not defined, as NiceMock, +// NaggyMock, and StrictMock cannot be nested. + +template +class NiceMock >; +template +class NiceMock >; +template +class NiceMock >; + +template +class NaggyMock >; +template +class NaggyMock >; +template +class NaggyMock >; + +template +class StrictMock >; +template +class StrictMock >; +template +class StrictMock >; + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ diff --git a/test/gmock/include/gmock/gmock-matchers.h b/test/gmock/include/gmock/gmock-matchers.h new file mode 100644 index 0000000..44055c9 --- /dev/null +++ b/test/gmock/include/gmock/gmock-matchers.h @@ -0,0 +1,3986 @@ +// 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 implements some commonly used argument matchers. More +// matchers can be defined by the user implementing the +// MatcherInterface interface if necessary. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ + +#include +#include +#include +#include +#include // NOLINT +#include +#include +#include +#include + +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" + +#if GTEST_LANG_CXX11 +#include // NOLINT -- must be after gtest.h +#endif + +namespace testing { + +// To implement a matcher Foo for type T, define: +// 1. a class FooMatcherImpl that implements the +// MatcherInterface interface, and +// 2. a factory function that creates a Matcher object from a +// FooMatcherImpl*. +// +// The two-level delegation design makes it possible to allow a user +// to write "v" instead of "Eq(v)" where a Matcher is expected, which +// is impossible if we pass matchers by pointers. It also eases +// ownership management as Matcher objects can now be copied like +// plain values. + +// MatchResultListener is an abstract class. Its << operator can be +// used by a matcher to explain why a value matches or doesn't match. +// +// TODO(wan@google.com): add method +// bool InterestedInWhy(bool result) const; +// to indicate whether the listener is interested in why the match +// result is 'result'. +class MatchResultListener { + public: + // Creates a listener object with the given underlying ostream. The + // listener does not own the ostream, and does not dereference it + // in the constructor or destructor. + explicit MatchResultListener(::std::ostream* os) : stream_(os) {} + virtual ~MatchResultListener() = 0; // Makes this class abstract. + + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template + MatchResultListener& operator<<(const T& x) { + if (stream_ != NULL) + *stream_ << x; + return *this; + } + + // Returns the underlying ostream. + ::std::ostream* stream() { return stream_; } + + // Returns true iff the listener is interested in an explanation of + // the match result. A matcher's MatchAndExplain() method can use + // this information to avoid generating the explanation when no one + // intends to hear it. + bool IsInterested() const { return stream_ != NULL; } + + private: + ::std::ostream* const stream_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); +}; + +inline MatchResultListener::~MatchResultListener() { +} + +// An instance of a subclass of this knows how to describe itself as a +// matcher. +class MatcherDescriberInterface { + public: + virtual ~MatcherDescriberInterface() {} + + // Describes this matcher to an ostream. The function should print + // a verb phrase that describes the property a value matching this + // matcher should have. The subject of the verb phrase is the value + // being matched. For example, the DescribeTo() method of the Gt(7) + // matcher prints "is greater than 7". + virtual void DescribeTo(::std::ostream* os) const = 0; + + // Describes the negation of this matcher to an ostream. For + // example, if the description of this matcher is "is greater than + // 7", the negated description could be "is not greater than 7". + // You are not required to override this when implementing + // MatcherInterface, but it is highly advised so that your matcher + // can produce good error messages. + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "not ("; + DescribeTo(os); + *os << ")"; + } +}; + +// The implementation of a matcher. +template +class MatcherInterface : public MatcherDescriberInterface { + public: + // Returns true iff the matcher matches x; also explains the match + // result to 'listener' if necessary (see the next paragraph), in + // the form of a non-restrictive relative clause ("which ...", + // "whose ...", etc) that describes x. For example, the + // MatchAndExplain() method of the Pointee(...) matcher should + // generate an explanation like "which points to ...". + // + // Implementations of MatchAndExplain() should add an explanation of + // the match result *if and only if* they can provide additional + // information that's not already present (or not obvious) in the + // print-out of x and the matcher's description. Whether the match + // succeeds is not a factor in deciding whether an explanation is + // needed, as sometimes the caller needs to print a failure message + // when the match succeeds (e.g. when the matcher is used inside + // Not()). + // + // For example, a "has at least 10 elements" matcher should explain + // what the actual element count is, regardless of the match result, + // as it is useful information to the reader; on the other hand, an + // "is empty" matcher probably only needs to explain what the actual + // size is when the match fails, as it's redundant to say that the + // size is 0 when the value is already known to be empty. + // + // You should override this method when defining a new matcher. + // + // It's the responsibility of the caller (Google Mock) to guarantee + // that 'listener' is not NULL. This helps to simplify a matcher's + // implementation when it doesn't care about the performance, as it + // can talk to 'listener' without checking its validity first. + // However, in order to implement dummy listeners efficiently, + // listener->stream() may be NULL. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; + + // Inherits these methods from MatcherDescriberInterface: + // virtual void DescribeTo(::std::ostream* os) const = 0; + // virtual void DescribeNegationTo(::std::ostream* os) const; +}; + +// A match result listener that stores the explanation in a string. +class StringMatchResultListener : public MatchResultListener { + public: + StringMatchResultListener() : MatchResultListener(&ss_) {} + + // Returns the explanation accumulated so far. + internal::string str() const { return ss_.str(); } + + // Clears the explanation accumulated so far. + void Clear() { ss_.str(""); } + + private: + ::std::stringstream ss_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StringMatchResultListener); +}; + +namespace internal { + +// A match result listener that ignores the explanation. +class DummyMatchResultListener : public MatchResultListener { + public: + DummyMatchResultListener() : MatchResultListener(NULL) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener); +}; + +// A match result listener that forwards the explanation to a given +// ostream. The difference between this and MatchResultListener is +// that the former is concrete. +class StreamMatchResultListener : public MatchResultListener { + public: + explicit StreamMatchResultListener(::std::ostream* os) + : MatchResultListener(os) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); +}; + +// An internal class for implementing Matcher, which will derive +// from it. We put functionalities common to all Matcher +// specializations here to avoid code duplication. +template +class MatcherBase { + public: + // Returns true iff the matcher matches x; also explains the match + // result to 'listener'. + bool MatchAndExplain(T x, MatchResultListener* listener) const { + return impl_->MatchAndExplain(x, listener); + } + + // Returns true iff this matcher matches x. + bool Matches(T x) const { + DummyMatchResultListener dummy; + return MatchAndExplain(x, &dummy); + } + + // Describes this matcher to an ostream. + void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } + + // Describes the negation of this matcher to an ostream. + void DescribeNegationTo(::std::ostream* os) const { + impl_->DescribeNegationTo(os); + } + + // Explains why x matches, or doesn't match, the matcher. + void ExplainMatchResultTo(T x, ::std::ostream* os) const { + StreamMatchResultListener listener(os); + MatchAndExplain(x, &listener); + } + + // Returns the describer for this matcher object; retains ownership + // of the describer, which is only guaranteed to be alive when + // this matcher object is alive. + const MatcherDescriberInterface* GetDescriber() const { + return impl_.get(); + } + + protected: + MatcherBase() {} + + // Constructs a matcher from its implementation. + explicit MatcherBase(const MatcherInterface* impl) + : impl_(impl) {} + + virtual ~MatcherBase() {} + + private: + // shared_ptr (util/gtl/shared_ptr.h) and linked_ptr have similar + // interfaces. The former dynamically allocates a chunk of memory + // to hold the reference count, while the latter tracks all + // references using a circular linked list without allocating + // memory. It has been observed that linked_ptr performs better in + // typical scenarios. However, shared_ptr can out-perform + // linked_ptr when there are many more uses of the copy constructor + // than the default constructor. + // + // If performance becomes a problem, we should see if using + // shared_ptr helps. + ::testing::internal::linked_ptr > impl_; +}; + +} // namespace internal + +// A Matcher is a copyable and IMMUTABLE (except by assignment) +// object that can check whether a value of type T matches. The +// implementation of Matcher is just a linked_ptr to const +// MatcherInterface, so copying is fairly cheap. Don't inherit +// from Matcher! +template +class Matcher : public internal::MatcherBase { + public: + // Constructs a null matcher. Needed for storing Matcher objects in STL + // containers. A default-constructed matcher is not yet initialized. You + // cannot use it until a valid value has been assigned to it. + Matcher() {} + + // Constructs a matcher from its implementation. + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Implicit constructor here allows people to write + // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes + Matcher(T value); // NOLINT +}; + +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a string +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const internal::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const internal::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +#if GTEST_HAS_STRING_PIECE_ +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a StringPiece +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const internal::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass StringPieces directly. + Matcher(StringPiece s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const internal::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass StringPieces directly. + Matcher(StringPiece s); // NOLINT +}; +#endif // GTEST_HAS_STRING_PIECE_ + +// The PolymorphicMatcher class template makes it easy to implement a +// polymorphic matcher (i.e. a matcher that can match values of more +// than one type, e.g. Eq(n) and NotNull()). +// +// To define a polymorphic matcher, a user should provide an Impl +// class that has a DescribeTo() method and a DescribeNegationTo() +// method, and define a member function (or member function template) +// +// bool MatchAndExplain(const Value& value, +// MatchResultListener* listener) const; +// +// See the definition of NotNull() for a complete example. +template +class PolymorphicMatcher { + public: + explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {} + + // Returns a mutable reference to the underlying matcher + // implementation object. + Impl& mutable_impl() { return impl_; } + + // Returns an immutable reference to the underlying matcher + // implementation object. + const Impl& impl() const { return impl_; } + + template + operator Matcher() const { + return Matcher(new MonomorphicImpl(impl_)); + } + + private: + template + class MonomorphicImpl : public MatcherInterface { + public: + explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} + + virtual void DescribeTo(::std::ostream* os) const { + impl_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + impl_.DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return impl_.MatchAndExplain(x, listener); + } + + private: + const Impl impl_; + + GTEST_DISALLOW_ASSIGN_(MonomorphicImpl); + }; + + Impl impl_; + + GTEST_DISALLOW_ASSIGN_(PolymorphicMatcher); +}; + +// Creates a matcher from its implementation. This is easier to use +// than the Matcher constructor as it doesn't require you to +// explicitly write the template argument, e.g. +// +// MakeMatcher(foo); +// vs +// Matcher(foo); +template +inline Matcher MakeMatcher(const MatcherInterface* impl) { + return Matcher(impl); +} + +// Creates a polymorphic matcher from its implementation. This is +// easier to use than the PolymorphicMatcher constructor as it +// doesn't require you to explicitly write the template argument, e.g. +// +// MakePolymorphicMatcher(foo); +// vs +// PolymorphicMatcher(foo); +template +inline PolymorphicMatcher MakePolymorphicMatcher(const Impl& impl) { + return PolymorphicMatcher(impl); +} + +// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION +// and MUST NOT BE USED IN USER CODE!!! +namespace internal { + +// The MatcherCastImpl class template is a helper for implementing +// MatcherCast(). We need this helper in order to partially +// specialize the implementation of MatcherCast() (C++ allows +// class/struct templates to be partially specialized, but not +// function templates.). + +// This general version is used when MatcherCast()'s argument is a +// polymorphic matcher (i.e. something that can be converted to a +// Matcher but is not one yet; for example, Eq(value)) or a value (for +// example, "hello"). +template +class MatcherCastImpl { + public: + static Matcher Cast(M polymorphic_matcher_or_value) { + // M can be a polymorhic matcher, in which case we want to use + // its conversion operator to create Matcher. Or it can be a value + // that should be passed to the Matcher's constructor. + // + // We can't call Matcher(polymorphic_matcher_or_value) when M is a + // polymorphic matcher because it'll be ambiguous if T has an implicit + // constructor from M (this usually happens when T has an implicit + // constructor from any type). + // + // It won't work to unconditionally implict_cast + // polymorphic_matcher_or_value to Matcher because it won't trigger + // a user-defined conversion from M to T if one exists (assuming M is + // a value). + return CastImpl( + polymorphic_matcher_or_value, + BooleanConstant< + internal::ImplicitlyConvertible >::value>()); + } + + private: + static Matcher CastImpl(M value, BooleanConstant) { + // M can't be implicitly converted to Matcher, so M isn't a polymorphic + // matcher. It must be a value then. Use direct initialization to create + // a matcher. + return Matcher(ImplicitCast_(value)); + } + + static Matcher CastImpl(M polymorphic_matcher_or_value, + BooleanConstant) { + // M is implicitly convertible to Matcher, which means that either + // M is a polymorhpic matcher or Matcher has an implicit constructor + // from M. In both cases using the implicit conversion will produce a + // matcher. + // + // Even if T has an implicit constructor from M, it won't be called because + // creating Matcher would require a chain of two user-defined conversions + // (first to create T from M and then to create Matcher from T). + return polymorphic_matcher_or_value; + } +}; + +// This more specialized version is used when MatcherCast()'s argument +// is already a Matcher. This only compiles when type T can be +// statically converted to type U. +template +class MatcherCastImpl > { + public: + static Matcher Cast(const Matcher& source_matcher) { + return Matcher(new Impl(source_matcher)); + } + + private: + class Impl : public MatcherInterface { + public: + explicit Impl(const Matcher& source_matcher) + : source_matcher_(source_matcher) {} + + // We delegate the matching logic to the source matcher. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return source_matcher_.MatchAndExplain(static_cast(x), listener); + } + + virtual void DescribeTo(::std::ostream* os) const { + source_matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + source_matcher_.DescribeNegationTo(os); + } + + private: + const Matcher source_matcher_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; +}; + +// This even more specialized version is used for efficiently casting +// a matcher to its own type. +template +class MatcherCastImpl > { + public: + static Matcher Cast(const Matcher& matcher) { return matcher; } +}; + +} // namespace internal + +// In order to be safe and clear, casting between different matcher +// types is done explicitly via MatcherCast(m), which takes a +// matcher m and returns a Matcher. It compiles only when T can be +// statically converted to the argument type of m. +template +inline Matcher MatcherCast(M matcher) { + return internal::MatcherCastImpl::Cast(matcher); +} + +// Implements SafeMatcherCast(). +// +// We use an intermediate class to do the actual safe casting as Nokia's +// Symbian compiler cannot decide between +// template ... (M) and +// template ... (const Matcher&) +// for function templates but can for member function templates. +template +class SafeMatcherCastImpl { + public: + // This overload handles polymorphic matchers and values only since + // monomorphic matchers are handled by the next one. + template + static inline Matcher Cast(M polymorphic_matcher_or_value) { + return internal::MatcherCastImpl::Cast(polymorphic_matcher_or_value); + } + + // This overload handles monomorphic matchers. + // + // In general, if type T can be implicitly converted to type U, we can + // safely convert a Matcher to a Matcher (i.e. Matcher is + // contravariant): just keep a copy of the original Matcher, convert the + // argument from type T to U, and then pass it to the underlying Matcher. + // The only exception is when U is a reference and T is not, as the + // underlying Matcher may be interested in the argument's address, which + // is not preserved in the conversion from T to U. + template + static inline Matcher Cast(const Matcher& matcher) { + // Enforce that T can be implicitly converted to U. + GTEST_COMPILE_ASSERT_((internal::ImplicitlyConvertible::value), + T_must_be_implicitly_convertible_to_U); + // Enforce that we are not converting a non-reference type T to a reference + // type U. + GTEST_COMPILE_ASSERT_( + internal::is_reference::value || !internal::is_reference::value, + cannot_convert_non_referentce_arg_to_reference); + // In case both T and U are arithmetic types, enforce that the + // conversion is not lossy. + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(T) RawT; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(U) RawU; + const bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther; + const bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther; + GTEST_COMPILE_ASSERT_( + kTIsOther || kUIsOther || + (internal::LosslessArithmeticConvertible::value), + conversion_of_arithmetic_types_must_be_lossless); + return MatcherCast(matcher); + } +}; + +template +inline Matcher SafeMatcherCast(const M& polymorphic_matcher) { + return SafeMatcherCastImpl::Cast(polymorphic_matcher); +} + +// A() returns a matcher that matches any value of type T. +template +Matcher A(); + +// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION +// and MUST NOT BE USED IN USER CODE!!! +namespace internal { + +// If the explanation is not empty, prints it to the ostream. +inline void PrintIfNotEmpty(const internal::string& explanation, + ::std::ostream* os) { + if (explanation != "" && os != NULL) { + *os << ", " << explanation; + } +} + +// Returns true if the given type name is easy to read by a human. +// This is used to decide whether printing the type of a value might +// be helpful. +inline bool IsReadableTypeName(const string& type_name) { + // We consider a type name readable if it's short or doesn't contain + // a template or function type. + return (type_name.length() <= 20 || + type_name.find_first_of("<(") == string::npos); +} + +// Matches the value against the given matcher, prints the value and explains +// the match result to the listener. Returns the match result. +// 'listener' must not be NULL. +// Value cannot be passed by const reference, because some matchers take a +// non-const argument. +template +bool MatchPrintAndExplain(Value& value, const Matcher& matcher, + MatchResultListener* listener) { + if (!listener->IsInterested()) { + // If the listener is not interested, we do not need to construct the + // inner explanation. + return matcher.Matches(value); + } + + StringMatchResultListener inner_listener; + const bool match = matcher.MatchAndExplain(value, &inner_listener); + + UniversalPrint(value, listener->stream()); +#if GTEST_HAS_RTTI + const string& type_name = GetTypeName(); + if (IsReadableTypeName(type_name)) + *listener->stream() << " (of type " << type_name << ")"; +#endif + PrintIfNotEmpty(inner_listener.str(), listener->stream()); + + return match; +} + +// An internal helper class for doing compile-time loop on a tuple's +// fields. +template +class TuplePrefix { + public: + // TuplePrefix::Matches(matcher_tuple, value_tuple) returns true + // iff the first N fields of matcher_tuple matches the first N + // fields of value_tuple, respectively. + template + static bool Matches(const MatcherTuple& matcher_tuple, + const ValueTuple& value_tuple) { + using ::std::tr1::get; + return TuplePrefix::Matches(matcher_tuple, value_tuple) + && get(matcher_tuple).Matches(get(value_tuple)); + } + + // TuplePrefix::ExplainMatchFailuresTo(matchers, values, os) + // describes failures in matching the first N fields of matchers + // against the first N fields of values. If there is no failure, + // nothing will be streamed to os. + template + static void ExplainMatchFailuresTo(const MatcherTuple& matchers, + const ValueTuple& values, + ::std::ostream* os) { + using ::std::tr1::tuple_element; + using ::std::tr1::get; + + // First, describes failures in the first N - 1 fields. + TuplePrefix::ExplainMatchFailuresTo(matchers, values, os); + + // Then describes the failure (if any) in the (N - 1)-th (0-based) + // field. + typename tuple_element::type matcher = + get(matchers); + typedef typename tuple_element::type Value; + Value value = get(values); + StringMatchResultListener listener; + if (!matcher.MatchAndExplain(value, &listener)) { + // TODO(wan): include in the message the name of the parameter + // as used in MOCK_METHOD*() when possible. + *os << " Expected arg #" << N - 1 << ": "; + get(matchers).DescribeTo(os); + *os << "\n Actual: "; + // We remove the reference in type Value to prevent the + // universal printer from printing the address of value, which + // isn't interesting to the user most of the time. The + // matcher's MatchAndExplain() method handles the case when + // the address is interesting. + internal::UniversalPrint(value, os); + PrintIfNotEmpty(listener.str(), os); + *os << "\n"; + } + } +}; + +// The base case. +template <> +class TuplePrefix<0> { + public: + template + static bool Matches(const MatcherTuple& /* matcher_tuple */, + const ValueTuple& /* value_tuple */) { + return true; + } + + template + static void ExplainMatchFailuresTo(const MatcherTuple& /* matchers */, + const ValueTuple& /* values */, + ::std::ostream* /* os */) {} +}; + +// TupleMatches(matcher_tuple, value_tuple) returns true iff all +// matchers in matcher_tuple match the corresponding fields in +// value_tuple. It is a compiler error if matcher_tuple and +// value_tuple have different number of fields or incompatible field +// types. +template +bool TupleMatches(const MatcherTuple& matcher_tuple, + const ValueTuple& value_tuple) { + using ::std::tr1::tuple_size; + // Makes sure that matcher_tuple and value_tuple have the same + // number of fields. + GTEST_COMPILE_ASSERT_(tuple_size::value == + tuple_size::value, + matcher_and_value_have_different_numbers_of_fields); + return TuplePrefix::value>:: + Matches(matcher_tuple, value_tuple); +} + +// Describes failures in matching matchers against values. If there +// is no failure, nothing will be streamed to os. +template +void ExplainMatchFailureTupleTo(const MatcherTuple& matchers, + const ValueTuple& values, + ::std::ostream* os) { + using ::std::tr1::tuple_size; + TuplePrefix::value>::ExplainMatchFailuresTo( + matchers, values, os); +} + +// TransformTupleValues and its helper. +// +// TransformTupleValuesHelper hides the internal machinery that +// TransformTupleValues uses to implement a tuple traversal. +template +class TransformTupleValuesHelper { + private: + typedef typename ::std::tr1::tuple_size TupleSize; + + public: + // For each member of tuple 't', taken in order, evaluates '*out++ = f(t)'. + // Returns the final value of 'out' in case the caller needs it. + static OutIter Run(Func f, const Tuple& t, OutIter out) { + return IterateOverTuple()(f, t, out); + } + + private: + template + struct IterateOverTuple { + OutIter operator() (Func f, const Tup& t, OutIter out) const { + *out++ = f(::std::tr1::get(t)); + return IterateOverTuple()(f, t, out); + } + }; + template + struct IterateOverTuple { + OutIter operator() (Func /* f */, const Tup& /* t */, OutIter out) const { + return out; + } + }; +}; + +// Successively invokes 'f(element)' on each element of the tuple 't', +// appending each result to the 'out' iterator. Returns the final value +// of 'out'. +template +OutIter TransformTupleValues(Func f, const Tuple& t, OutIter out) { + return TransformTupleValuesHelper::Run(f, t, out); +} + +// Implements A(). +template +class AnyMatcherImpl : public MatcherInterface { + public: + virtual bool MatchAndExplain( + T /* x */, MatchResultListener* /* listener */) const { return true; } + virtual void DescribeTo(::std::ostream* os) const { *os << "is anything"; } + virtual void DescribeNegationTo(::std::ostream* os) const { + // This is mostly for completeness' safe, as it's not very useful + // to write Not(A()). However we cannot completely rule out + // such a possibility, and it doesn't hurt to be prepared. + *os << "never matches"; + } +}; + +// Implements _, a matcher that matches any value of any +// type. This is a polymorphic matcher, so we need a template type +// conversion operator to make it appearing as a Matcher for any +// type T. +class AnythingMatcher { + public: + template + operator Matcher() const { return A(); } +}; + +// Implements a matcher that compares a given value with a +// pre-supplied value using one of the ==, <=, <, etc, operators. The +// two values being compared don't have to have the same type. +// +// The matcher defined here is polymorphic (for example, Eq(5) can be +// used to match an int, a short, a double, etc). Therefore we use +// a template type conversion operator in the implementation. +// +// We define this as a macro in order to eliminate duplicated source +// code. +// +// The following template definition assumes that the Rhs parameter is +// a "bare" type (i.e. neither 'const T' nor 'T&'). +#define GMOCK_IMPLEMENT_COMPARISON_MATCHER_( \ + name, op, relation, negated_relation) \ + template class name##Matcher { \ + public: \ + explicit name##Matcher(const Rhs& rhs) : rhs_(rhs) {} \ + template \ + operator Matcher() const { \ + return MakeMatcher(new Impl(rhs_)); \ + } \ + private: \ + template \ + class Impl : public MatcherInterface { \ + public: \ + explicit Impl(const Rhs& rhs) : rhs_(rhs) {} \ + virtual bool MatchAndExplain(\ + Lhs lhs, MatchResultListener* /* listener */) const { \ + return lhs op rhs_; \ + } \ + virtual void DescribeTo(::std::ostream* os) const { \ + *os << relation " "; \ + UniversalPrint(rhs_, os); \ + } \ + virtual void DescribeNegationTo(::std::ostream* os) const { \ + *os << negated_relation " "; \ + UniversalPrint(rhs_, os); \ + } \ + private: \ + Rhs rhs_; \ + GTEST_DISALLOW_ASSIGN_(Impl); \ + }; \ + Rhs rhs_; \ + GTEST_DISALLOW_ASSIGN_(name##Matcher); \ + } + +// Implements Eq(v), Ge(v), Gt(v), Le(v), Lt(v), and Ne(v) +// respectively. +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Eq, ==, "is equal to", "isn't equal to"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ge, >=, "is >=", "isn't >="); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Gt, >, "is >", "isn't >"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Le, <=, "is <=", "isn't <="); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Lt, <, "is <", "isn't <"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ne, !=, "isn't equal to", "is equal to"); + +#undef GMOCK_IMPLEMENT_COMPARISON_MATCHER_ + +// Implements the polymorphic IsNull() matcher, which matches any raw or smart +// pointer that is NULL. +class IsNullMatcher { + public: + template + bool MatchAndExplain(const Pointer& p, + MatchResultListener* /* listener */) const { + return GetRawPointer(p) == NULL; + } + + void DescribeTo(::std::ostream* os) const { *os << "is NULL"; } + void DescribeNegationTo(::std::ostream* os) const { + *os << "isn't NULL"; + } +}; + +// Implements the polymorphic NotNull() matcher, which matches any raw or smart +// pointer that is not NULL. +class NotNullMatcher { + public: + template + bool MatchAndExplain(const Pointer& p, + MatchResultListener* /* listener */) const { + return GetRawPointer(p) != NULL; + } + + void DescribeTo(::std::ostream* os) const { *os << "isn't NULL"; } + void DescribeNegationTo(::std::ostream* os) const { + *os << "is NULL"; + } +}; + +// Ref(variable) matches any argument that is a reference to +// 'variable'. This matcher is polymorphic as it can match any +// super type of the type of 'variable'. +// +// The RefMatcher template class implements Ref(variable). It can +// only be instantiated with a reference type. This prevents a user +// from mistakenly using Ref(x) to match a non-reference function +// argument. For example, the following will righteously cause a +// compiler error: +// +// int n; +// Matcher m1 = Ref(n); // This won't compile. +// Matcher m2 = Ref(n); // This will compile. +template +class RefMatcher; + +template +class RefMatcher { + // Google Mock is a generic framework and thus needs to support + // mocking any function types, including those that take non-const + // reference arguments. Therefore the template parameter T (and + // Super below) can be instantiated to either a const type or a + // non-const type. + public: + // RefMatcher() takes a T& instead of const T&, as we want the + // compiler to catch using Ref(const_value) as a matcher for a + // non-const reference. + explicit RefMatcher(T& x) : object_(x) {} // NOLINT + + template + operator Matcher() const { + // By passing object_ (type T&) to Impl(), which expects a Super&, + // we make sure that Super is a super type of T. In particular, + // this catches using Ref(const_value) as a matcher for a + // non-const reference, as you cannot implicitly convert a const + // reference to a non-const reference. + return MakeMatcher(new Impl(object_)); + } + + private: + template + class Impl : public MatcherInterface { + public: + explicit Impl(Super& x) : object_(x) {} // NOLINT + + // MatchAndExplain() takes a Super& (as opposed to const Super&) + // in order to match the interface MatcherInterface. + virtual bool MatchAndExplain( + Super& x, MatchResultListener* listener) const { + *listener << "which is located @" << static_cast(&x); + return &x == &object_; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "references the variable "; + UniversalPrinter::Print(object_, os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "does not reference the variable "; + UniversalPrinter::Print(object_, os); + } + + private: + const Super& object_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + T& object_; + + GTEST_DISALLOW_ASSIGN_(RefMatcher); +}; + +// Polymorphic helper functions for narrow and wide string matchers. +inline bool CaseInsensitiveCStringEquals(const char* lhs, const char* rhs) { + return String::CaseInsensitiveCStringEquals(lhs, rhs); +} + +inline bool CaseInsensitiveCStringEquals(const wchar_t* lhs, + const wchar_t* rhs) { + return String::CaseInsensitiveWideCStringEquals(lhs, rhs); +} + +// String comparison for narrow or wide strings that can have embedded NUL +// characters. +template +bool CaseInsensitiveStringEquals(const StringType& s1, + const StringType& s2) { + // Are the heads equal? + if (!CaseInsensitiveCStringEquals(s1.c_str(), s2.c_str())) { + return false; + } + + // Skip the equal heads. + const typename StringType::value_type nul = 0; + const size_t i1 = s1.find(nul), i2 = s2.find(nul); + + // Are we at the end of either s1 or s2? + if (i1 == StringType::npos || i2 == StringType::npos) { + return i1 == i2; + } + + // Are the tails equal? + return CaseInsensitiveStringEquals(s1.substr(i1 + 1), s2.substr(i2 + 1)); +} + +// String matchers. + +// Implements equality-based string matchers like StrEq, StrCaseNe, and etc. +template +class StrEqualityMatcher { + public: + StrEqualityMatcher(const StringType& str, bool expect_eq, + bool case_sensitive) + : string_(str), expect_eq_(expect_eq), case_sensitive_(case_sensitive) {} + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + if (s == NULL) { + return !expect_eq_; + } + return MatchAndExplain(StringType(s), listener); + } + + // Matches anything that can convert to StringType. + // + // This is a template, not just a plain function with const StringType&, + // because StringPiece has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const StringType& s2(s); + const bool eq = case_sensitive_ ? s2 == string_ : + CaseInsensitiveStringEquals(s2, string_); + return expect_eq_ == eq; + } + + void DescribeTo(::std::ostream* os) const { + DescribeToHelper(expect_eq_, os); + } + + void DescribeNegationTo(::std::ostream* os) const { + DescribeToHelper(!expect_eq_, os); + } + + private: + void DescribeToHelper(bool expect_eq, ::std::ostream* os) const { + *os << (expect_eq ? "is " : "isn't "); + *os << "equal to "; + if (!case_sensitive_) { + *os << "(ignoring case) "; + } + UniversalPrint(string_, os); + } + + const StringType string_; + const bool expect_eq_; + const bool case_sensitive_; + + GTEST_DISALLOW_ASSIGN_(StrEqualityMatcher); +}; + +// Implements the polymorphic HasSubstr(substring) matcher, which +// can be used as a Matcher as long as T can be converted to a +// string. +template +class HasSubstrMatcher { + public: + explicit HasSubstrMatcher(const StringType& substring) + : substring_(substring) {} + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + return s != NULL && MatchAndExplain(StringType(s), listener); + } + + // Matches anything that can convert to StringType. + // + // This is a template, not just a plain function with const StringType&, + // because StringPiece has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const StringType& s2(s); + return s2.find(substring_) != StringType::npos; + } + + // Describes what this matcher matches. + void DescribeTo(::std::ostream* os) const { + *os << "has substring "; + UniversalPrint(substring_, os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "has no substring "; + UniversalPrint(substring_, os); + } + + private: + const StringType substring_; + + GTEST_DISALLOW_ASSIGN_(HasSubstrMatcher); +}; + +// Implements the polymorphic StartsWith(substring) matcher, which +// can be used as a Matcher as long as T can be converted to a +// string. +template +class StartsWithMatcher { + public: + explicit StartsWithMatcher(const StringType& prefix) : prefix_(prefix) { + } + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + return s != NULL && MatchAndExplain(StringType(s), listener); + } + + // Matches anything that can convert to StringType. + // + // This is a template, not just a plain function with const StringType&, + // because StringPiece has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const StringType& s2(s); + return s2.length() >= prefix_.length() && + s2.substr(0, prefix_.length()) == prefix_; + } + + void DescribeTo(::std::ostream* os) const { + *os << "starts with "; + UniversalPrint(prefix_, os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't start with "; + UniversalPrint(prefix_, os); + } + + private: + const StringType prefix_; + + GTEST_DISALLOW_ASSIGN_(StartsWithMatcher); +}; + +// Implements the polymorphic EndsWith(substring) matcher, which +// can be used as a Matcher as long as T can be converted to a +// string. +template +class EndsWithMatcher { + public: + explicit EndsWithMatcher(const StringType& suffix) : suffix_(suffix) {} + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + return s != NULL && MatchAndExplain(StringType(s), listener); + } + + // Matches anything that can convert to StringType. + // + // This is a template, not just a plain function with const StringType&, + // because StringPiece has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const StringType& s2(s); + return s2.length() >= suffix_.length() && + s2.substr(s2.length() - suffix_.length()) == suffix_; + } + + void DescribeTo(::std::ostream* os) const { + *os << "ends with "; + UniversalPrint(suffix_, os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't end with "; + UniversalPrint(suffix_, os); + } + + private: + const StringType suffix_; + + GTEST_DISALLOW_ASSIGN_(EndsWithMatcher); +}; + +// Implements polymorphic matchers MatchesRegex(regex) and +// ContainsRegex(regex), which can be used as a Matcher as long as +// T can be converted to a string. +class MatchesRegexMatcher { + public: + MatchesRegexMatcher(const RE* regex, bool full_match) + : regex_(regex), full_match_(full_match) {} + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + return s != NULL && MatchAndExplain(internal::string(s), listener); + } + + // Matches anything that can convert to internal::string. + // + // This is a template, not just a plain function with const internal::string&, + // because StringPiece has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const internal::string& s2(s); + return full_match_ ? RE::FullMatch(s2, *regex_) : + RE::PartialMatch(s2, *regex_); + } + + void DescribeTo(::std::ostream* os) const { + *os << (full_match_ ? "matches" : "contains") + << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't " << (full_match_ ? "match" : "contain") + << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + private: + const internal::linked_ptr regex_; + const bool full_match_; + + GTEST_DISALLOW_ASSIGN_(MatchesRegexMatcher); +}; + +// Implements a matcher that compares the two fields of a 2-tuple +// using one of the ==, <=, <, etc, operators. The two fields being +// compared don't have to have the same type. +// +// The matcher defined here is polymorphic (for example, Eq() can be +// used to match a tuple, a tuple, +// etc). Therefore we use a template type conversion operator in the +// implementation. +// +// We define this as a macro in order to eliminate duplicated source +// code. +#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(name, op, relation) \ + class name##2Matcher { \ + public: \ + template \ + operator Matcher< ::std::tr1::tuple >() const { \ + return MakeMatcher(new Impl< ::std::tr1::tuple >); \ + } \ + template \ + operator Matcher&>() const { \ + return MakeMatcher(new Impl&>); \ + } \ + private: \ + template \ + class Impl : public MatcherInterface { \ + public: \ + virtual bool MatchAndExplain( \ + Tuple args, \ + MatchResultListener* /* listener */) const { \ + return ::std::tr1::get<0>(args) op ::std::tr1::get<1>(args); \ + } \ + virtual void DescribeTo(::std::ostream* os) const { \ + *os << "are " relation; \ + } \ + virtual void DescribeNegationTo(::std::ostream* os) const { \ + *os << "aren't " relation; \ + } \ + }; \ + } + +// Implements Eq(), Ge(), Gt(), Le(), Lt(), and Ne() respectively. +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Eq, ==, "an equal pair"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_( + Ge, >=, "a pair where the first >= the second"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_( + Gt, >, "a pair where the first > the second"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_( + Le, <=, "a pair where the first <= the second"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_( + Lt, <, "a pair where the first < the second"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ne, !=, "an unequal pair"); + +#undef GMOCK_IMPLEMENT_COMPARISON2_MATCHER_ + +// Implements the Not(...) matcher for a particular argument type T. +// We do not nest it inside the NotMatcher class template, as that +// will prevent different instantiations of NotMatcher from sharing +// the same NotMatcherImpl class. +template +class NotMatcherImpl : public MatcherInterface { + public: + explicit NotMatcherImpl(const Matcher& matcher) + : matcher_(matcher) {} + + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return !matcher_.MatchAndExplain(x, listener); + } + + virtual void DescribeTo(::std::ostream* os) const { + matcher_.DescribeNegationTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + matcher_.DescribeTo(os); + } + + private: + const Matcher matcher_; + + GTEST_DISALLOW_ASSIGN_(NotMatcherImpl); +}; + +// Implements the Not(m) matcher, which matches a value that doesn't +// match matcher m. +template +class NotMatcher { + public: + explicit NotMatcher(InnerMatcher matcher) : matcher_(matcher) {} + + // This template type conversion operator allows Not(m) to be used + // to match any type m can match. + template + operator Matcher() const { + return Matcher(new NotMatcherImpl(SafeMatcherCast(matcher_))); + } + + private: + InnerMatcher matcher_; + + GTEST_DISALLOW_ASSIGN_(NotMatcher); +}; + +// Implements the AllOf(m1, m2) matcher for a particular argument type +// T. We do not nest it inside the BothOfMatcher class template, as +// that will prevent different instantiations of BothOfMatcher from +// sharing the same BothOfMatcherImpl class. +template +class BothOfMatcherImpl : public MatcherInterface { + public: + BothOfMatcherImpl(const Matcher& matcher1, const Matcher& matcher2) + : matcher1_(matcher1), matcher2_(matcher2) {} + + virtual void DescribeTo(::std::ostream* os) const { + *os << "("; + matcher1_.DescribeTo(os); + *os << ") and ("; + matcher2_.DescribeTo(os); + *os << ")"; + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "("; + matcher1_.DescribeNegationTo(os); + *os << ") or ("; + matcher2_.DescribeNegationTo(os); + *os << ")"; + } + + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + // If either matcher1_ or matcher2_ doesn't match x, we only need + // to explain why one of them fails. + StringMatchResultListener listener1; + if (!matcher1_.MatchAndExplain(x, &listener1)) { + *listener << listener1.str(); + return false; + } + + StringMatchResultListener listener2; + if (!matcher2_.MatchAndExplain(x, &listener2)) { + *listener << listener2.str(); + return false; + } + + // Otherwise we need to explain why *both* of them match. + const internal::string s1 = listener1.str(); + const internal::string s2 = listener2.str(); + + if (s1 == "") { + *listener << s2; + } else { + *listener << s1; + if (s2 != "") { + *listener << ", and " << s2; + } + } + return true; + } + + private: + const Matcher matcher1_; + const Matcher matcher2_; + + GTEST_DISALLOW_ASSIGN_(BothOfMatcherImpl); +}; + +#if GTEST_LANG_CXX11 +// MatcherList provides mechanisms for storing a variable number of matchers in +// a list structure (ListType) and creating a combining matcher from such a +// list. +// The template is defined recursively using the following template paramters: +// * kSize is the length of the MatcherList. +// * Head is the type of the first matcher of the list. +// * Tail denotes the types of the remaining matchers of the list. +template +struct MatcherList { + typedef MatcherList MatcherListTail; + typedef ::std::pair ListType; + + // BuildList stores variadic type values in a nested pair structure. + // Example: + // MatcherList<3, int, string, float>::BuildList(5, "foo", 2.0) will return + // the corresponding result of type pair>. + static ListType BuildList(const Head& matcher, const Tail&... tail) { + return ListType(matcher, MatcherListTail::BuildList(tail...)); + } + + // CreateMatcher creates a Matcher from a given list of matchers (built + // by BuildList()). CombiningMatcher is used to combine the matchers of the + // list. CombiningMatcher must implement MatcherInterface and have a + // constructor taking two Matchers as input. + template class CombiningMatcher> + static Matcher CreateMatcher(const ListType& matchers) { + return Matcher(new CombiningMatcher( + SafeMatcherCast(matchers.first), + MatcherListTail::template CreateMatcher( + matchers.second))); + } +}; + +// The following defines the base case for the recursive definition of +// MatcherList. +template +struct MatcherList<2, Matcher1, Matcher2> { + typedef ::std::pair ListType; + + static ListType BuildList(const Matcher1& matcher1, + const Matcher2& matcher2) { + return ::std::pair(matcher1, matcher2); + } + + template class CombiningMatcher> + static Matcher CreateMatcher(const ListType& matchers) { + return Matcher(new CombiningMatcher( + SafeMatcherCast(matchers.first), + SafeMatcherCast(matchers.second))); + } +}; + +// VariadicMatcher is used for the variadic implementation of +// AllOf(m_1, m_2, ...) and AnyOf(m_1, m_2, ...). +// CombiningMatcher is used to recursively combine the provided matchers +// (of type Args...). +template