/*
 *
 * An exhaustive set of tests for parsing both valid and invalid protobuf
 * input, with buffer breaks in arbitrary places.
 *
 * Tests to add:
 * - string/bytes
 * - unknown field handler called appropriately
 * - unknown fields can be inserted in random places
 * - fuzzing of valid input
 * - resource limits (max stack depth, max string len)
 * - testing of groups
 * - more throrough testing of sequences
 * - test skipping of submessages
 * - test suspending the decoder
 * - buffers that are close enough to the end of the address space that
 *   pointers overflow (this might be difficult).
 * - a few "kitchen sink" examples (one proto that uses all types, lots
 *   of submsg/sequences, etc.
 * - test different handlers at every level and whether handlers fire at
 *   the correct field path.
 * - test skips that extend past the end of current buffer (where decoder
 *   returns value greater than the size param).
 */

#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS  // For PRIuS, etc.
#endif

#include <inttypes.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sstream>

#include "tests/test_util.h"
#include "tests/upb_test.h"
#include "tests/pb/test_decoder.upbdefs.h"

#ifdef AMALGAMATED
#include "upb.h"
#else  // AMALGAMATED
#include "upb/handlers.h"
#include "upb/pb/decoder.h"
#include "upb/pb/varint.int.h"
#include "upb/upb.h"
#endif  // !AMALGAMATED

#include "upb/port_def.inc"

#undef PRINT_FAILURE
#define PRINT_FAILURE(expr)                                           \
  fprintf(stderr, "Assertion failed: %s:%d\n", __FILE__, __LINE__);   \
  fprintf(stderr, "expr: %s\n", #expr);                               \
  if (testhash) {                                                     \
    fprintf(stderr, "assertion failed running test %x.\n", testhash); \
    if (!filter_hash) {                                               \
      fprintf(stderr,                                                 \
              "Run with the arg %x to run only this test. "           \
              "(This will also turn on extra debugging output)\n",    \
              testhash);                                              \
    }                                                                 \
    fprintf(stderr, "Failed at %02.2f%% through tests.\n",            \
            (float)completed * 100 / total);                          \
  }

#define MAX_NESTING 64

#define LINE(x) x "\n"

uint32_t filter_hash = 0;
double completed;
double total;
double *count;

enum TestMode {
  COUNT_ONLY = 1,
  NO_HANDLERS = 2,
  ALL_HANDLERS = 3
} test_mode;

// Copied from decoder.c, since this is not a public interface.
typedef struct {
  uint8_t native_wire_type;
  bool is_numeric;
} upb_decoder_typeinfo;

static const upb_decoder_typeinfo upb_decoder_types[] = {
  {UPB_WIRE_TYPE_END_GROUP,   false},  // ENDGROUP
  {UPB_WIRE_TYPE_64BIT,       true},   // DOUBLE
  {UPB_WIRE_TYPE_32BIT,       true},   // FLOAT
  {UPB_WIRE_TYPE_VARINT,      true},   // INT64
  {UPB_WIRE_TYPE_VARINT,      true},   // UINT64
  {UPB_WIRE_TYPE_VARINT,      true},   // INT32
  {UPB_WIRE_TYPE_64BIT,       true},   // FIXED64
  {UPB_WIRE_TYPE_32BIT,       true},   // FIXED32
  {UPB_WIRE_TYPE_VARINT,      true},   // BOOL
  {UPB_WIRE_TYPE_DELIMITED,   false},  // STRING
  {UPB_WIRE_TYPE_START_GROUP, false},  // GROUP
  {UPB_WIRE_TYPE_DELIMITED,   false},  // MESSAGE
  {UPB_WIRE_TYPE_DELIMITED,   false},  // BYTES
  {UPB_WIRE_TYPE_VARINT,      true},   // UINT32
  {UPB_WIRE_TYPE_VARINT,      true},   // ENUM
  {UPB_WIRE_TYPE_32BIT,       true},   // SFIXED32
  {UPB_WIRE_TYPE_64BIT,       true},   // SFIXED64
  {UPB_WIRE_TYPE_VARINT,      true},   // SINT32
  {UPB_WIRE_TYPE_VARINT,      true},   // SINT64
};

#ifndef USE_GOOGLE
using std::string;
#endif

void vappendf(string* str, const char *format, va_list args) {
  va_list copy;
  _upb_va_copy(copy, args);

  int count = vsnprintf(NULL, 0, format, args);
  if (count >= 0)
  {
    UPB_ASSERT(count < 32768);
    char *buffer = new char[count + 1];
    UPB_ASSERT(buffer);
    count = vsnprintf(buffer, count + 1, format, copy);
    UPB_ASSERT(count >= 0);
    str->append(buffer, count);
    delete [] buffer;
  }
  va_end(copy);
}

void appendf(string* str, const char *fmt, ...) {
  va_list args;
  va_start(args, fmt);
  vappendf(str, fmt, args);
  va_end(args);
}

void PrintBinary(const string& str) {
  for (size_t i = 0; i < str.size(); i++) {
    if (isprint(str[i])) {
      fprintf(stderr, "%c", str[i]);
    } else {
      fprintf(stderr, "\\x%02x", (int)(uint8_t)str[i]);
    }
  }
}

/* Routines for building arbitrary protos *************************************/

const string empty;

string cat(const string& a, const string& b,
           const string& c = empty,
           const string& d = empty,
           const string& e = empty,
           const string& f = empty,
           const string& g = empty,
           const string& h = empty,
           const string& i = empty,
           const string& j = empty,
           const string& k = empty,
           const string& l = empty) {
  string ret;
  ret.reserve(a.size() + b.size() + c.size() + d.size() + e.size() + f.size() +
              g.size() + h.size() + i.size() + j.size() + k.size() + l.size());
  ret.append(a);
  ret.append(b);
  ret.append(c);
  ret.append(d);
  ret.append(e);
  ret.append(f);
  ret.append(g);
  ret.append(h);
  ret.append(i);
  ret.append(j);
  ret.append(k);
  ret.append(l);
  return ret;
}

template <typename T>
string num2string(T num) {
  std::ostringstream ss;
  ss << num;
  return ss.str();
}

string varint(uint64_t x) {
  char buf[UPB_PB_VARINT_MAX_LEN];
  size_t len = upb_vencode64(x, buf);
  return string(buf, len);
}

// TODO: proper byte-swapping for big-endian machines.
string fixed32(void *data) { return string(static_cast<char*>(data), 4); }
string fixed64(void *data) { return string(static_cast<char*>(data), 8); }

string delim(const string& buf) { return cat(varint(buf.size()), buf); }
string uint32(uint32_t u32) { return fixed32(&u32); }
string uint64(uint64_t u64) { return fixed64(&u64); }
string flt(float f) { return fixed32(&f); }
string dbl(double d) { return fixed64(&d); }
string zz32(int32_t x) { return varint(upb_zzenc_32(x)); }
string zz64(int64_t x) { return varint(upb_zzenc_64(x)); }

string tag(uint32_t fieldnum, char wire_type) {
  return varint((fieldnum << 3) | wire_type);
}

string submsg(uint32_t fn, const string& buf) {
  return cat( tag(fn, UPB_WIRE_TYPE_DELIMITED), delim(buf) );
}

string group(uint32_t fn, const string& buf) {
  return cat(tag(fn, UPB_WIRE_TYPE_START_GROUP), buf,
             tag(fn, UPB_WIRE_TYPE_END_GROUP));
}

// Like delim()/submsg(), but intentionally encodes an incorrect length.
// These help test when a delimited boundary doesn't land in the right place.
string badlen_delim(int err, const string& buf) {
  return cat(varint(buf.size() + err), buf);
}

string badlen_submsg(int err, uint32_t fn, const string& buf) {
  return cat( tag(fn, UPB_WIRE_TYPE_DELIMITED), badlen_delim(err, buf) );
}


/* A set of handlers that covers all .proto types *****************************/

// The handlers simply append to a string indicating what handlers were called.
// This string is similar to protobuf text format but fields are referred to by
// number instead of name and sequences are explicitly delimited.  We indent
// using the closure depth to test that the stack of closures is properly
// handled.

int closures[MAX_NESTING];
string output;

void indentbuf(string *buf, int depth) {
  buf->append(2 * depth, ' ');
}

#define NUMERIC_VALUE_HANDLER(member, ctype, fmt)                   \
  bool value_##member(int* depth, const uint32_t* num, ctype val) { \
    indentbuf(&output, *depth);                                     \
    appendf(&output, "%" PRIu32 ":%" fmt "\n", *num, val);          \
    return true;                                                    \
  }

NUMERIC_VALUE_HANDLER(uint32, uint32_t, PRIu32)
NUMERIC_VALUE_HANDLER(uint64, uint64_t, PRIu64)
NUMERIC_VALUE_HANDLER(int32,  int32_t,  PRId32)
NUMERIC_VALUE_HANDLER(int64,  int64_t,  PRId64)
NUMERIC_VALUE_HANDLER(float,  float,    "g")
NUMERIC_VALUE_HANDLER(double, double,   "g")

bool value_bool(int* depth, const uint32_t* num, bool val) {
  indentbuf(&output, *depth);
  appendf(&output, "%" PRIu32 ":%s\n", *num, val ? "true" : "false");
  return true;
}

int* startstr(int* depth, const uint32_t* num, size_t size_hint) {
  indentbuf(&output, *depth);
  appendf(&output, "%" PRIu32 ":(%zu)\"", *num, size_hint);
  return depth + 1;
}

size_t value_string(int* depth, const uint32_t* num, const char* buf,
                    size_t n, const upb_bufhandle* handle) {
  UPB_UNUSED(num);
  UPB_UNUSED(depth);
  output.append(buf, n);
  ASSERT(handle == &global_handle);
  return n;
}

bool endstr(int* depth, const uint32_t* num) {
  UPB_UNUSED(num);
  output.append("\n");
  indentbuf(&output, *depth);
  appendf(&output, "%" PRIu32 ":\"\n", *num);
  return true;
}

int* startsubmsg(int* depth, const uint32_t* num) {
  indentbuf(&output, *depth);
  appendf(&output, "%" PRIu32 ":{\n", *num);
  return depth + 1;
}

bool endsubmsg(int* depth, const uint32_t* num) {
  UPB_UNUSED(num);
  indentbuf(&output, *depth);
  output.append("}\n");
  return true;
}

int* startseq(int* depth, const uint32_t* num) {
  indentbuf(&output, *depth);
  appendf(&output, "%" PRIu32 ":[\n", *num);
  return depth + 1;
}

bool endseq(int* depth, const uint32_t* num) {
  UPB_UNUSED(num);
  indentbuf(&output, *depth);
  output.append("]\n");
  return true;
}

bool startmsg(int* depth) {
  indentbuf(&output, *depth);
  output.append("<\n");
  return true;
}

bool endmsg(int* depth, upb_status* status) {
  UPB_UNUSED(status);
  indentbuf(&output, *depth);
  output.append(">\n");
  return true;
}

void free_uint32(void *val) {
  uint32_t *u32 = static_cast<uint32_t*>(val);
  delete u32;
}

template<class T, bool F(int*, const uint32_t*, T)>
void doreg(upb::HandlersPtr h, uint32_t num) {
  upb::FieldDefPtr f = h.message_def().FindFieldByNumber(num);
  ASSERT(f);
  ASSERT(h.SetValueHandler<T>(f, UpbBind(F, new uint32_t(num))));
  if (f.IsSequence()) {
    ASSERT(h.SetStartSequenceHandler(f, UpbBind(startseq, new uint32_t(num))));
    ASSERT(h.SetEndSequenceHandler(f, UpbBind(endseq, new uint32_t(num))));
  }
}

// The repeated field number to correspond to the given non-repeated field
// number.
uint32_t rep_fn(uint32_t fn) {
  return (UPB_MAX_FIELDNUMBER - 1000) + fn;
}

#define NOP_FIELD 40
#define UNKNOWN_FIELD 666

template <class T, bool F(int*, const uint32_t*, T)>
void reg(upb::HandlersPtr h, upb_descriptortype_t type) {
  // We register both a repeated and a non-repeated field for every type.
  // For the non-repeated field we make the field number the same as the
  // type.  For the repeated field we make it a function of the type.
  doreg<T, F>(h, type);
  doreg<T, F>(h, rep_fn(type));
}

void regseq(upb::HandlersPtr h, upb::FieldDefPtr f, uint32_t num) {
  ASSERT(h.SetStartSequenceHandler(f, UpbBind(startseq, new uint32_t(num))));
  ASSERT(h.SetEndSequenceHandler(f, UpbBind(endseq, new uint32_t(num))));
}

void reg_subm(upb::HandlersPtr h, uint32_t num) {
  upb::FieldDefPtr f = h.message_def().FindFieldByNumber(num);
  ASSERT(f);
  if (f.IsSequence()) regseq(h, f, num);
  ASSERT(
      h.SetStartSubMessageHandler(f, UpbBind(startsubmsg, new uint32_t(num))));
  ASSERT(h.SetEndSubMessageHandler(f, UpbBind(endsubmsg, new uint32_t(num))));
}

void reg_str(upb::HandlersPtr h, uint32_t num) {
  upb::FieldDefPtr f = h.message_def().FindFieldByNumber(num);
  ASSERT(f);
  if (f.IsSequence()) regseq(h, f, num);
  ASSERT(h.SetStartStringHandler(f, UpbBind(startstr, new uint32_t(num))));
  ASSERT(h.SetEndStringHandler(f, UpbBind(endstr, new uint32_t(num))));
  ASSERT(h.SetStringHandler(f, UpbBind(value_string, new uint32_t(num))));
}

struct HandlerRegisterData {
  TestMode mode;
};

void callback(const void *closure, upb::Handlers* h_ptr) {
  upb::HandlersPtr h(h_ptr);
  const HandlerRegisterData* data =
      static_cast<const HandlerRegisterData*>(closure);
  if (data->mode == ALL_HANDLERS) {
    h.SetStartMessageHandler(UpbMakeHandler(startmsg));
    h.SetEndMessageHandler(UpbMakeHandler(endmsg));

    // Register handlers for each type.
    reg<double,   value_double>(h, UPB_DESCRIPTOR_TYPE_DOUBLE);
    reg<float,    value_float> (h, UPB_DESCRIPTOR_TYPE_FLOAT);
    reg<int64_t,  value_int64> (h, UPB_DESCRIPTOR_TYPE_INT64);
    reg<uint64_t, value_uint64>(h, UPB_DESCRIPTOR_TYPE_UINT64);
    reg<int32_t,  value_int32> (h, UPB_DESCRIPTOR_TYPE_INT32);
    reg<uint64_t, value_uint64>(h, UPB_DESCRIPTOR_TYPE_FIXED64);
    reg<uint32_t, value_uint32>(h, UPB_DESCRIPTOR_TYPE_FIXED32);
    reg<bool,     value_bool>  (h, UPB_DESCRIPTOR_TYPE_BOOL);
    reg<uint32_t, value_uint32>(h, UPB_DESCRIPTOR_TYPE_UINT32);
    reg<int32_t,  value_int32> (h, UPB_DESCRIPTOR_TYPE_ENUM);
    reg<int32_t,  value_int32> (h, UPB_DESCRIPTOR_TYPE_SFIXED32);
    reg<int64_t,  value_int64> (h, UPB_DESCRIPTOR_TYPE_SFIXED64);
    reg<int32_t,  value_int32> (h, UPB_DESCRIPTOR_TYPE_SINT32);
    reg<int64_t,  value_int64> (h, UPB_DESCRIPTOR_TYPE_SINT64);

    reg_str(h, UPB_DESCRIPTOR_TYPE_STRING);
    reg_str(h, UPB_DESCRIPTOR_TYPE_BYTES);
    reg_str(h, rep_fn(UPB_DESCRIPTOR_TYPE_STRING));
    reg_str(h, rep_fn(UPB_DESCRIPTOR_TYPE_BYTES));

    // Register submessage/group handlers that are self-recursive
    // to this type, eg: message M { optional M m = 1; }
    reg_subm(h, UPB_DESCRIPTOR_TYPE_MESSAGE);
    reg_subm(h, rep_fn(UPB_DESCRIPTOR_TYPE_MESSAGE));

    if (h.message_def().full_name() == std::string("DecoderTest")) {
      reg_subm(h, UPB_DESCRIPTOR_TYPE_GROUP);
      reg_subm(h, rep_fn(UPB_DESCRIPTOR_TYPE_GROUP));
    }

    // For NOP_FIELD we register no handlers, so we can pad a proto freely without
    // changing the output.
  }
}

/* Running of test cases ******************************************************/

const upb::Handlers *global_handlers;
upb::pb::DecoderMethodPtr global_method;

upb::pb::DecoderPtr CreateDecoder(upb::Arena* arena,
                                  upb::pb::DecoderMethodPtr method,
                                  upb::Sink sink, upb::Status* status) {
  upb::pb::DecoderPtr ret =
      upb::pb::DecoderPtr::Create(arena, method, sink, status);
  ret.set_max_nesting(MAX_NESTING);
  return ret;
}

uint32_t Hash(const string& proto, const string* expected_output, size_t seam1,
              size_t seam2, bool may_skip) {
  uint32_t hash = upb_murmur_hash2(proto.c_str(), proto.size(), 0);
  if (expected_output)
    hash = upb_murmur_hash2(expected_output->c_str(), expected_output->size(), hash);
  hash = upb_murmur_hash2(&seam1, sizeof(seam1), hash);
  hash = upb_murmur_hash2(&seam2, sizeof(seam2), hash);
  hash = upb_murmur_hash2(&may_skip, sizeof(may_skip), hash);
  return hash;
}

void CheckBytesParsed(upb::pb::DecoderPtr decoder, size_t ofs) {
  // We can't have parsed more data than the decoder callback is telling us it
  // parsed.
  ASSERT(decoder.BytesParsed() <= ofs);

  // The difference between what we've decoded and what the decoder has accepted
  // represents the internally buffered amount.  This amount should not exceed
  // this value which comes from decoder.int.h.
  ASSERT(ofs <= (decoder.BytesParsed() + UPB_DECODER_MAX_RESIDUAL_BYTES));
}

static bool parse(VerboseParserEnvironment* env,
                  upb::pb::DecoderPtr decoder, int bytes) {
  CheckBytesParsed(decoder, env->ofs());
  bool ret = env->ParseBuffer(bytes);
  if (ret) {
    CheckBytesParsed(decoder, env->ofs());
  }

  return ret;
}

void do_run_decoder(VerboseParserEnvironment* env, upb::pb::DecoderPtr decoder,
                    const string& proto, const string* expected_output,
                    size_t i, size_t j, bool may_skip) {
  env->Reset(proto.c_str(), proto.size(), may_skip, expected_output == NULL);
  decoder.Reset();

  testhash = Hash(proto, expected_output, i, j, may_skip);
  if (filter_hash && testhash != filter_hash) return;
  if (test_mode != COUNT_ONLY) {
    output.clear();

    if (filter_hash) {
      fprintf(stderr, "RUNNING TEST CASE, hash=%x\n", testhash);
      fprintf(stderr, "Input (len=%u): ", (unsigned)proto.size());
      PrintBinary(proto);
      fprintf(stderr, "\n");
      if (expected_output) {
        if (test_mode == ALL_HANDLERS) {
          fprintf(stderr, "Expected output: %s\n", expected_output->c_str());
        } else if (test_mode == NO_HANDLERS) {
          fprintf(stderr,
                  "No handlers are registered, BUT if they were "
                  "the expected output would be: %s\n",
                  expected_output->c_str());
        }
      } else {
        fprintf(stderr, "Expected to FAIL\n");
      }
    }

    bool ok = env->Start() &&
              parse(env, decoder, i) &&
              parse(env, decoder, j - i) &&
              parse(env, decoder, -1) &&
              env->End();

    ASSERT(env->CheckConsistency());

    if (test_mode == ALL_HANDLERS) {
      if (expected_output) {
        if (output != *expected_output) {
          fprintf(stderr, "Text mismatch: '%s' vs '%s'\n",
                  output.c_str(), expected_output->c_str());
        }
        ASSERT(ok);
        ASSERT(output == *expected_output);
      } else {
        if (ok) {
          fprintf(stderr, "Didn't expect ok result, but got output: '%s'\n",
                  output.c_str());
        }
        ASSERT(!ok);
      }
    }
  }
  (*count)++;
}

void run_decoder(const string& proto, const string* expected_output) {
  VerboseParserEnvironment env(filter_hash != 0);
  upb::Sink sink(global_handlers, &closures[0]);
  upb::pb::DecoderPtr decoder = CreateDecoder(env.arena(), global_method, sink, env.status());
  env.ResetBytesSink(decoder.input());
  for (size_t i = 0; i < proto.size(); i++) {
    for (size_t j = i; j < UPB_MIN(proto.size(), i + 5); j++) {
      do_run_decoder(&env, decoder, proto, expected_output, i, j, true);
      if (env.SkippedWithNull()) {
        do_run_decoder(&env, decoder, proto, expected_output, i, j, false);
      }
    }
  }
  testhash = 0;
}

const static string thirty_byte_nop = cat(
    tag(NOP_FIELD, UPB_WIRE_TYPE_DELIMITED), delim(string(30, 'X')) );

// Indents and wraps text as if it were a submessage with this field number
string wrap_text(int32_t fn, const string& text) {
  string wrapped_text = text;
  size_t pos = 0;
  string replace_with = "\n  ";
  while ((pos = wrapped_text.find("\n", pos)) != string::npos &&
         pos != wrapped_text.size() - 1) {
    wrapped_text.replace(pos, 1, replace_with);
    pos += replace_with.size();
  }
  wrapped_text = cat(
      LINE("<"),
      num2string(fn), LINE(":{")
      "  ", wrapped_text,
      LINE("}")
      LINE(">"));
  return wrapped_text;
}

void assert_successful_parse(const string& proto,
                             const char *expected_fmt, ...) {
  string expected_text;
  va_list args;
  va_start(args, expected_fmt);
  vappendf(&expected_text, expected_fmt, args);
  va_end(args);
  // To test both middle-of-buffer and end-of-buffer code paths,
  // repeat once with no-op padding data at the end of buffer.
  run_decoder(proto, &expected_text);
  run_decoder(cat( proto, thirty_byte_nop ), &expected_text);

  // Test that this also works when wrapped in a submessage or group.
  // Indent the expected text one level and wrap it.
  string wrapped_text1 = wrap_text(UPB_DESCRIPTOR_TYPE_MESSAGE, expected_text);
  string wrapped_text2 = wrap_text(UPB_DESCRIPTOR_TYPE_GROUP, expected_text);

  run_decoder(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, proto), &wrapped_text1);
  run_decoder(group(UPB_DESCRIPTOR_TYPE_GROUP, proto), &wrapped_text2);
}

void assert_does_not_parse_at_eof(const string& proto) {
  run_decoder(proto, NULL);

  // Also test that we fail to parse at end-of-submessage, not just
  // end-of-message.  But skip this if we have no handlers, because in that
  // case we won't descend into the submessage.
  if (test_mode != NO_HANDLERS) {
    run_decoder(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, proto), NULL);
    run_decoder(cat(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, proto),
                    thirty_byte_nop), NULL);
  }
}

void assert_does_not_parse(const string& proto) {
  // Test that the error is caught both at end-of-buffer and middle-of-buffer.
  assert_does_not_parse_at_eof(proto);
  assert_does_not_parse_at_eof(cat( proto, thirty_byte_nop ));
}


/* The actual tests ***********************************************************/

void test_premature_eof_for_type(upb_descriptortype_t type) {
  // Incomplete values for each wire type.
  static const string incompletes[6] = {
    string("\x80"),     // UPB_WIRE_TYPE_VARINT
    string("abcdefg"),  // UPB_WIRE_TYPE_64BIT
    string("\x80"),     // UPB_WIRE_TYPE_DELIMITED (partial length)
    string(),           // UPB_WIRE_TYPE_START_GROUP (no value required)
    string(),           // UPB_WIRE_TYPE_END_GROUP (no value required)
    string("abc")       // UPB_WIRE_TYPE_32BIT
  };

  uint32_t fieldnum = type;
  uint32_t rep_fieldnum = rep_fn(type);
  int wire_type = upb_decoder_types[type].native_wire_type;
  const string& incomplete = incompletes[wire_type];

  // EOF before a known non-repeated value.
  assert_does_not_parse_at_eof(tag(fieldnum, wire_type));

  // EOF before a known repeated value.
  assert_does_not_parse_at_eof(tag(rep_fieldnum, wire_type));

  // EOF before an unknown value.
  assert_does_not_parse_at_eof(tag(UNKNOWN_FIELD, wire_type));

  // EOF inside a known non-repeated value.
  assert_does_not_parse_at_eof(
      cat( tag(fieldnum, wire_type), incomplete ));

  // EOF inside a known repeated value.
  assert_does_not_parse_at_eof(
      cat( tag(rep_fieldnum, wire_type), incomplete ));

  // EOF inside an unknown value.
  assert_does_not_parse_at_eof(
      cat( tag(UNKNOWN_FIELD, wire_type), incomplete ));

  if (wire_type == UPB_WIRE_TYPE_DELIMITED) {
    // EOF in the middle of delimited data for known non-repeated value.
    assert_does_not_parse_at_eof(
        cat( tag(fieldnum, wire_type), varint(1) ));

    // EOF in the middle of delimited data for known repeated value.
    assert_does_not_parse_at_eof(
        cat( tag(rep_fieldnum, wire_type), varint(1) ));

    // EOF in the middle of delimited data for unknown value.
    assert_does_not_parse_at_eof(
        cat( tag(UNKNOWN_FIELD, wire_type), varint(1) ));

    if (type == UPB_DESCRIPTOR_TYPE_MESSAGE) {
      // Submessage ends in the middle of a value.
      string incomplete_submsg =
          cat ( tag(UPB_DESCRIPTOR_TYPE_INT32, UPB_WIRE_TYPE_VARINT),
                incompletes[UPB_WIRE_TYPE_VARINT] );
      assert_does_not_parse(
          cat( tag(fieldnum, UPB_WIRE_TYPE_DELIMITED),
               varint(incomplete_submsg.size()),
               incomplete_submsg ));
    }
  } else {
    // Packed region ends in the middle of a value.
    assert_does_not_parse(
        cat( tag(rep_fieldnum, UPB_WIRE_TYPE_DELIMITED),
             varint(incomplete.size()),
             incomplete ));

    // EOF in the middle of packed region.
    assert_does_not_parse_at_eof(
        cat( tag(rep_fieldnum, UPB_WIRE_TYPE_DELIMITED), varint(1) ));
  }
}

// "33" and "66" are just two random values that all numeric types can
// represent.
void test_valid_data_for_type(upb_descriptortype_t type,
                              const string& enc33, const string& enc66) {
  uint32_t fieldnum = type;
  uint32_t rep_fieldnum = rep_fn(type);
  int wire_type = upb_decoder_types[type].native_wire_type;

  // Non-repeated
  assert_successful_parse(
      cat( tag(fieldnum, wire_type), enc33,
           tag(fieldnum, wire_type), enc66 ),
      LINE("<")
      LINE("%u:33")
      LINE("%u:66")
      LINE(">"), fieldnum, fieldnum);

  // Non-packed repeated.
  assert_successful_parse(
      cat( tag(rep_fieldnum, wire_type), enc33,
           tag(rep_fieldnum, wire_type), enc66 ),
      LINE("<")
      LINE("%u:[")
      LINE("  %u:33")
      LINE("  %u:66")
      LINE("]")
      LINE(">"), rep_fieldnum, rep_fieldnum, rep_fieldnum);

  // Packed repeated.
  assert_successful_parse(
      cat( tag(rep_fieldnum, UPB_WIRE_TYPE_DELIMITED),
           delim(cat( enc33, enc66 )) ),
      LINE("<")
      LINE("%u:[")
      LINE("  %u:33")
      LINE("  %u:66")
      LINE("]")
      LINE(">"), rep_fieldnum, rep_fieldnum, rep_fieldnum);
}

void test_valid_data_for_signed_type(upb_descriptortype_t type,
                                     const string& enc33, const string& enc66) {
  uint32_t fieldnum = type;
  uint32_t rep_fieldnum = rep_fn(type);
  int wire_type = upb_decoder_types[type].native_wire_type;

  // Non-repeated
  assert_successful_parse(
      cat( tag(fieldnum, wire_type), enc33,
           tag(fieldnum, wire_type), enc66 ),
      LINE("<")
      LINE("%u:33")
      LINE("%u:-66")
      LINE(">"), fieldnum, fieldnum);

  // Non-packed repeated.
  assert_successful_parse(
      cat( tag(rep_fieldnum, wire_type), enc33,
           tag(rep_fieldnum, wire_type), enc66 ),
      LINE("<")
      LINE("%u:[")
      LINE("  %u:33")
      LINE("  %u:-66")
      LINE("]")
      LINE(">"), rep_fieldnum, rep_fieldnum, rep_fieldnum);

  // Packed repeated.
  assert_successful_parse(
      cat( tag(rep_fieldnum, UPB_WIRE_TYPE_DELIMITED),
           delim(cat( enc33, enc66 )) ),
      LINE("<")
      LINE("%u:[")
      LINE("  %u:33")
      LINE("  %u:-66")
      LINE("]")
      LINE(">"), rep_fieldnum, rep_fieldnum, rep_fieldnum);
}

// Test that invalid protobufs are properly detected (without crashing) and
// have an error reported.  Field numbers match registered handlers above.
void test_invalid() {
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_DOUBLE);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_FLOAT);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_INT64);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_UINT64);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_INT32);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_FIXED64);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_FIXED32);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_BOOL);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_STRING);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_BYTES);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_UINT32);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_ENUM);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_SFIXED32);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_SFIXED64);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_SINT32);
  test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_SINT64);

  // EOF inside a tag's varint.
  assert_does_not_parse_at_eof( string("\x80") );

  // EOF inside a known group.
  // TODO(haberman): add group to decoder test schema.
  //assert_does_not_parse_at_eof( tag(4, UPB_WIRE_TYPE_START_GROUP) );

  // EOF inside an unknown group.
  assert_does_not_parse_at_eof( tag(UNKNOWN_FIELD, UPB_WIRE_TYPE_START_GROUP) );

  // End group that we are not currently in.
  assert_does_not_parse( tag(4, UPB_WIRE_TYPE_END_GROUP) );

  // Field number is 0.
  assert_does_not_parse(
      cat( tag(0, UPB_WIRE_TYPE_DELIMITED), varint(0) ));
  // The previous test alone did not catch this particular pattern which could
  // corrupt the internal state.
  assert_does_not_parse(
      cat( tag(0, UPB_WIRE_TYPE_64BIT), uint64(0) ));

  // Field number is too large.
  assert_does_not_parse(
      cat( tag(UPB_MAX_FIELDNUMBER + 1, UPB_WIRE_TYPE_DELIMITED),
           varint(0) ));

  // Known group inside a submessage has ENDGROUP tag AFTER submessage end.
  assert_does_not_parse(
      cat ( submsg(UPB_DESCRIPTOR_TYPE_MESSAGE,
                   tag(UPB_DESCRIPTOR_TYPE_GROUP, UPB_WIRE_TYPE_START_GROUP)),
            tag(UPB_DESCRIPTOR_TYPE_GROUP, UPB_WIRE_TYPE_END_GROUP)));

  // Unknown string extends past enclosing submessage.
  assert_does_not_parse(
      cat (badlen_submsg(-1, UPB_DESCRIPTOR_TYPE_MESSAGE,
                         submsg(12345, string("   "))),
           submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, string("     "))));

  // Unknown fixed-length field extends past enclosing submessage.
  assert_does_not_parse(
      cat (badlen_submsg(-1, UPB_DESCRIPTOR_TYPE_MESSAGE,
                         cat( tag(12345, UPB_WIRE_TYPE_64BIT), uint64(0))),
           submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, string("     "))));

  // Test exceeding the resource limit of stack depth.
  if (test_mode != NO_HANDLERS) {
    string buf;
    for (int i = 0; i <= MAX_NESTING; i++) {
      buf.assign(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, buf));
    }
    assert_does_not_parse(buf);
  }
}

void test_valid() {
  // Empty protobuf.
  assert_successful_parse(string(""), "<\n>\n");

  // Empty protobuf where we never call PutString between
  // StartString/EndString.

  // Randomly generated hash for this test, hope it doesn't conflict with others
  // by chance.
  const uint32_t emptyhash = 0x5709be8e;
  if (!filter_hash || filter_hash == testhash) {
    testhash = emptyhash;
    upb::Status status;
    upb::Arena arena;
    upb::Sink sink(global_handlers, &closures[0]);
    upb::pb::DecoderPtr decoder =
        CreateDecoder(&arena, global_method, sink, &status);
    output.clear();
    bool ok = upb::PutBuffer(std::string(), decoder.input());
    ASSERT(ok);
    ASSERT(status.ok());
    if (test_mode == ALL_HANDLERS) {
      ASSERT(output == string("<\n>\n"));
    }
  }

  test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_DOUBLE,
                                  dbl(33),
                                  dbl(-66));
  test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_FLOAT, flt(33), flt(-66));
  test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_INT64,
                                  varint(33),
                                  varint(-66));
  test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_INT32,
                                  varint(33),
                                  varint(-66));
  test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_ENUM,
                                  varint(33),
                                  varint(-66));
  test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_SFIXED32,
                                  uint32(33),
                                  uint32(-66));
  test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_SFIXED64,
                                  uint64(33),
                                  uint64(-66));
  test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_SINT32,
                                  zz32(33),
                                  zz32(-66));
  test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_SINT64,
                                  zz64(33),
                                  zz64(-66));

  test_valid_data_for_type(UPB_DESCRIPTOR_TYPE_UINT64, varint(33), varint(66));
  test_valid_data_for_type(UPB_DESCRIPTOR_TYPE_UINT32, varint(33), varint(66));
  test_valid_data_for_type(UPB_DESCRIPTOR_TYPE_FIXED64, uint64(33), uint64(66));
  test_valid_data_for_type(UPB_DESCRIPTOR_TYPE_FIXED32, uint32(33), uint32(66));

  // Unknown fields.
  int int32_type = UPB_DESCRIPTOR_TYPE_INT32;
  int msg_type = UPB_DESCRIPTOR_TYPE_MESSAGE;
  assert_successful_parse(
      cat( tag(12345, UPB_WIRE_TYPE_VARINT), varint(2345678) ),
      "<\n>\n");
  assert_successful_parse(
      cat( tag(12345, UPB_WIRE_TYPE_32BIT), uint32(2345678) ),
      "<\n>\n");
  assert_successful_parse(
      cat( tag(12345, UPB_WIRE_TYPE_64BIT), uint64(2345678) ),
      "<\n>\n");
  assert_successful_parse(
      submsg(12345, string("                ")),
      "<\n>\n");

  // Unknown field inside a known submessage.
  assert_successful_parse(
      submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, submsg(12345, string("   "))),
      LINE("<")
      LINE("%u:{")
      LINE("  <")
      LINE("  >")
      LINE("}")
      LINE(">"), UPB_DESCRIPTOR_TYPE_MESSAGE);

  assert_successful_parse(
      cat (submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, submsg(12345, string("   "))),
           tag(UPB_DESCRIPTOR_TYPE_INT32, UPB_WIRE_TYPE_VARINT),
           varint(5)),
      LINE("<")
      LINE("%u:{")
      LINE("  <")
      LINE("  >")
      LINE("}")
      LINE("%u:5")
      LINE(">"), UPB_DESCRIPTOR_TYPE_MESSAGE, UPB_DESCRIPTOR_TYPE_INT32);

  // This triggered a previous bug in the decoder.
  assert_successful_parse(
      cat( tag(UPB_DESCRIPTOR_TYPE_SFIXED32, UPB_WIRE_TYPE_VARINT),
           varint(0) ),
      "<\n>\n");

  assert_successful_parse(
      cat(
        submsg(UPB_DESCRIPTOR_TYPE_MESSAGE,
          submsg(UPB_DESCRIPTOR_TYPE_MESSAGE,
            cat( tag(int32_type, UPB_WIRE_TYPE_VARINT), varint(2345678),
                 tag(12345, UPB_WIRE_TYPE_VARINT), varint(2345678) ))),
        tag(int32_type, UPB_WIRE_TYPE_VARINT), varint(22222)),
      LINE("<")
      LINE("%u:{")
      LINE("  <")
      LINE("  %u:{")
      LINE("    <")
      LINE("    %u:2345678")
      LINE("    >")
      LINE("  }")
      LINE("  >")
      LINE("}")
      LINE("%u:22222")
      LINE(">"), msg_type, msg_type, int32_type, int32_type);

  assert_successful_parse(
      cat( tag(UPB_DESCRIPTOR_TYPE_INT32, UPB_WIRE_TYPE_VARINT), varint(1),
           tag(12345, UPB_WIRE_TYPE_VARINT), varint(2345678) ),
      LINE("<")
      LINE("%u:1")
      LINE(">"), UPB_DESCRIPTOR_TYPE_INT32);

  // String inside submsg.
  uint32_t msg_fn = UPB_DESCRIPTOR_TYPE_MESSAGE;
  assert_successful_parse(
      submsg(msg_fn,
             cat ( tag(UPB_DESCRIPTOR_TYPE_STRING, UPB_WIRE_TYPE_DELIMITED),
                   delim(string("abcde"))
                 )
             ),
      LINE("<")
      LINE("%u:{")
      LINE("  <")
      LINE("  %u:(5)\"abcde")
      LINE("    %u:\"")
      LINE("  >")
      LINE("}")
      LINE(">"), msg_fn, UPB_DESCRIPTOR_TYPE_STRING,
                 UPB_DESCRIPTOR_TYPE_STRING);

  // Test implicit startseq/endseq.
  uint32_t repfl_fn = rep_fn(UPB_DESCRIPTOR_TYPE_FLOAT);
  uint32_t repdb_fn = rep_fn(UPB_DESCRIPTOR_TYPE_DOUBLE);
  assert_successful_parse(
      cat( tag(repfl_fn, UPB_WIRE_TYPE_32BIT), flt(33),
           tag(repdb_fn, UPB_WIRE_TYPE_64BIT), dbl(66) ),
      LINE("<")
      LINE("%u:[")
      LINE("  %u:33")
      LINE("]")
      LINE("%u:[")
      LINE("  %u:66")
      LINE("]")
      LINE(">"), repfl_fn, repfl_fn, repdb_fn, repdb_fn);

  // Submessage tests.
  assert_successful_parse(
      submsg(msg_fn, submsg(msg_fn, submsg(msg_fn, string()))),
      LINE("<")
      LINE("%u:{")
      LINE("  <")
      LINE("  %u:{")
      LINE("    <")
      LINE("    %u:{")
      LINE("      <")
      LINE("      >")
      LINE("    }")
      LINE("    >")
      LINE("  }")
      LINE("  >")
      LINE("}")
      LINE(">"), msg_fn, msg_fn, msg_fn);

  uint32_t repm_fn = rep_fn(UPB_DESCRIPTOR_TYPE_MESSAGE);
  assert_successful_parse(
      submsg(repm_fn, submsg(repm_fn, string())),
      LINE("<")
      LINE("%u:[")
      LINE("  %u:{")
      LINE("    <")
      LINE("    %u:[")
      LINE("      %u:{")
      LINE("        <")
      LINE("        >")
      LINE("      }")
      LINE("    ]")
      LINE("    >")
      LINE("  }")
      LINE("]")
      LINE(">"), repm_fn, repm_fn, repm_fn, repm_fn);

  // Test unknown group.
  uint32_t unknown_group_fn = 12321;
  assert_successful_parse(
      cat( tag(unknown_group_fn, UPB_WIRE_TYPE_START_GROUP),
           tag(unknown_group_fn, UPB_WIRE_TYPE_END_GROUP) ),
      LINE("<")
      LINE(">")
  );

  // Test some unknown fields inside an unknown group.
  const string unknown_group_with_data =
      cat(
          tag(unknown_group_fn, UPB_WIRE_TYPE_START_GROUP),
          tag(12345, UPB_WIRE_TYPE_VARINT), varint(2345678),
          tag(123456789, UPB_WIRE_TYPE_32BIT), uint32(2345678),
          tag(123477, UPB_WIRE_TYPE_64BIT), uint64(2345678),
          tag(123, UPB_WIRE_TYPE_DELIMITED), varint(0),
          tag(unknown_group_fn, UPB_WIRE_TYPE_END_GROUP)
         );

  // Nested unknown group with data.
  assert_successful_parse(
      cat(
           tag(unknown_group_fn, UPB_WIRE_TYPE_START_GROUP),
           unknown_group_with_data,
           tag(unknown_group_fn, UPB_WIRE_TYPE_END_GROUP),
           tag(UPB_DESCRIPTOR_TYPE_INT32, UPB_WIRE_TYPE_VARINT), varint(1)
         ),
      LINE("<")
      LINE("%u:1")
      LINE(">"),
      UPB_DESCRIPTOR_TYPE_INT32
  );

  assert_successful_parse(
      cat( tag(unknown_group_fn, UPB_WIRE_TYPE_START_GROUP),
           tag(unknown_group_fn + 1, UPB_WIRE_TYPE_START_GROUP),
           tag(unknown_group_fn + 1, UPB_WIRE_TYPE_END_GROUP),
           tag(unknown_group_fn, UPB_WIRE_TYPE_END_GROUP) ),
      LINE("<")
      LINE(">")
  );

  // Staying within the stack limit should work properly.
  string buf;
  string textbuf;
  int total = MAX_NESTING - 1;
  for (int i = 0; i < total; i++) {
    buf.assign(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, buf));
    indentbuf(&textbuf, i);
    textbuf.append("<\n");
    indentbuf(&textbuf, i);
    appendf(&textbuf, "%u:{\n", UPB_DESCRIPTOR_TYPE_MESSAGE);
  }
  indentbuf(&textbuf, total);
  textbuf.append("<\n");
  indentbuf(&textbuf, total);
  textbuf.append(">\n");
  for (int i = 0; i < total; i++) {
    indentbuf(&textbuf, total - i - 1);
    textbuf.append("}\n");
    indentbuf(&textbuf, total - i - 1);
    textbuf.append(">\n");
  }
  // Have to use run_decoder directly, because we are at max nesting and can't
  // afford the extra nesting that assert_successful_parse() will do.
  run_decoder(buf, &textbuf);
}

void empty_callback(const void *closure, upb::Handlers* h_ptr) {}

void test_emptyhandlers(upb::SymbolTable* symtab) {
  // Create an empty handlers to make sure that the decoder can handle empty
  // messages.
  HandlerRegisterData handlerdata;
  handlerdata.mode = test_mode;

  upb::HandlerCache handler_cache(empty_callback, &handlerdata);
  upb::pb::CodeCache pb_code_cache(&handler_cache);

  upb::MessageDefPtr md = upb::MessageDefPtr(Empty_getmsgdef(symtab->ptr()));
  global_handlers = handler_cache.Get(md);
  global_method = pb_code_cache.Get(md);

  // TODO: also test the case where a message has fields, but the fields are
  // submessage fields and have no handlers. This also results in a decoder
  // method with no field-handling code.

  // Ensure that the method can run with empty and non-empty input.
  string test_unknown_field_msg =
    cat(tag(1, UPB_WIRE_TYPE_VARINT), varint(42),
        tag(2, UPB_WIRE_TYPE_DELIMITED), delim("My test data"));
  const struct {
    const char* data;
    size_t length;
  } testdata[] = {
    { "", 0 },
    { test_unknown_field_msg.data(), test_unknown_field_msg.size() },
    { NULL, 0 },
  };
  for (int i = 0; testdata[i].data; i++) {
    VerboseParserEnvironment env(filter_hash != 0);
    upb::Sink sink(global_method.dest_handlers(), &closures[0]);
    upb::pb::DecoderPtr decoder =
        CreateDecoder(env.arena(), global_method, sink, env.status());
    env.ResetBytesSink(decoder.input());
    env.Reset(testdata[i].data, testdata[i].length, true, false);
    ASSERT(env.Start());
    ASSERT(env.ParseBuffer(-1));
    ASSERT(env.End());
    ASSERT(env.CheckConsistency());
  }
}

void run_tests() {
  HandlerRegisterData handlerdata;
  handlerdata.mode = test_mode;

  upb::SymbolTable symtab;
  upb::HandlerCache handler_cache(callback, &handlerdata);
  upb::pb::CodeCache pb_code_cache(&handler_cache);

  upb::MessageDefPtr md(DecoderTest_getmsgdef(symtab.ptr()));
  global_handlers = handler_cache.Get(md);
  global_method = pb_code_cache.Get(md);
  completed = 0;

  test_invalid();
  test_valid();

  test_emptyhandlers(&symtab);
}

extern "C" {

int run_tests(int argc, char *argv[]) {
  if (argc > 1)
    filter_hash = strtol(argv[1], NULL, 16);
  for (int i = 0; i < MAX_NESTING; i++) {
    closures[i] = i;
  }

  // Count tests.
  count = &total;
  total = 0;
  test_mode = COUNT_ONLY;
  run_tests();
  count = &completed;

  total *= 2;  // NO_HANDLERS, ALL_HANDLERS.

  test_mode = NO_HANDLERS;
  run_tests();

  test_mode = ALL_HANDLERS;
  run_tests();

  printf("All tests passed, %d assertions.\n", num_assertions);
  return 0;
}

}
