// Copyright 2008 The RE2 Authors.  All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Test StringGenerator.

#include <stdint.h>
#include <string>

#include "util/test.h"
#include "util/utf.h"
#include "re2/testing/string_generator.h"
#include "re2/testing/regexp_generator.h"

namespace re2 {

// Returns i to the e.
static int64_t IntegerPower(int i, int e) {
  int64_t p = 1;
  while (e-- > 0)
    p *= i;
  return p;
}

// Checks that for given settings of the string generator:
//   * it generates strings that are non-decreasing in length.
//   * strings of the same length are sorted in alphabet order.
//   * it doesn't generate the same string twice.
//   * it generates the right number of strings.
//
// If all of these hold, the StringGenerator is behaving.
// Assumes that the alphabet is sorted, so that the generated
// strings can just be compared lexicographically.
static void RunTest(int len, const std::string& alphabet, bool donull) {
  StringGenerator g(len, Explode(alphabet));

  int n = 0;
  int last_l = -1;
  std::string last_s;

  if (donull) {
    g.GenerateNULL();
    EXPECT_TRUE(g.HasNext());
    StringPiece sp = g.Next();
    EXPECT_EQ(sp.data(), static_cast<const char*>(NULL));
    EXPECT_EQ(sp.size(), 0);
  }

  while (g.HasNext()) {
    std::string s = std::string(g.Next());
    n++;

    // Check that all characters in s appear in alphabet.
    for (const char *p = s.c_str(); *p != '\0'; ) {
      Rune r;
      p += chartorune(&r, p);
      EXPECT_TRUE(utfrune(alphabet.c_str(), r) != NULL);
    }

    // Check that string is properly ordered w.r.t. previous string.
    int l = utflen(s.c_str());
    EXPECT_LE(l, len);
    if (last_l < l) {
      last_l = l;
    } else {
      EXPECT_EQ(last_l, l);
      EXPECT_LT(last_s, s);
    }
    last_s = s;
  }

  // Check total string count.
  int64_t m = 0;
  int alpha = utflen(alphabet.c_str());
  if (alpha == 0)  // Degenerate case.
    len = 0;
  for (int i = 0; i <= len; i++)
    m += IntegerPower(alpha, i);
  EXPECT_EQ(n, m);
}

TEST(StringGenerator, NoLength) {
  RunTest(0, "abc", false);
}

TEST(StringGenerator, NoLengthNoAlphabet) {
  RunTest(0, "", false);
}

TEST(StringGenerator, NoAlphabet) {
  RunTest(5, "", false);
}

TEST(StringGenerator, Simple) {
  RunTest(3, "abc", false);
}

TEST(StringGenerator, UTF8) {
  RunTest(4, "abc\xE2\x98\xBA", false);
}

TEST(StringGenerator, GenNULL) {
  RunTest(0, "abc", true);
  RunTest(0, "", true);
  RunTest(5, "", true);
  RunTest(3, "abc", true);
  RunTest(4, "abc\xE2\x98\xBA", true);
}

}  // namespace re2
