Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/ots/tests/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 43 kB image not shown  

Quelle  cff_charstring_test.cc   Sprache: C

 
// Copyright (c) 2010-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cff_charstring.h"

#include <gtest/gtest.h>

#include <climits>
#include <vector>

#include "cff.h"

// Returns a biased number for callsubr and callgsubr operators.
#define GET_SUBR_NUMBER(n) ((n) - 107)
#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0]))

namespace {

// A constant which is used in AddSubr function below.
const int kOpPrefix = INT_MAX;

// Encodes an operator |op| to 1 or more bytes and pushes them to |out_bytes|.
// Returns true if the conversion succeeds.
bool EncodeOperator(int op, std::vector<uint8_t> *out_bytes) {
  if (op < 0) {
    return false;
  }
  if (op <= 11) {
    out_bytes->push_back(op);
    return true;
  }
  if (op == 12) {
    return false;
  }
  if (op <= 27) {
    out_bytes->push_back(op);
    return true;
  }
  if (op == 28) {
    return false;
  }
  if (op <= 31) {
    out_bytes->push_back(op);
    return true;
  }

  const uint8_t upper = (op & 0xff00u) >> 8;
  const uint8_t lower = op & 0xffu;
  if (upper != 12) {
    return false;
  }
  out_bytes->push_back(upper);
  out_bytes->push_back(lower);
  return true;
}

// Encodes a number |num| to 1 or more bytes and pushes them to |out_bytes|.
// Returns true if the conversion succeeds. The function does not support 16.16
// Fixed number.
bool EncodeNumber(int num, std::vector<uint8_t> *out_bytes) {
  if (num >= -107 && num <= 107) {
    out_bytes->push_back(num + 139);
    return true;
  }
  if (num >= 108 && num <= 1131) {
    const uint8_t v = ((num - 108) / 256) + 247;
    const uint8_t w = (num - 108) % 256;
    out_bytes->push_back(v);
    out_bytes->push_back(w);
    return true;
  }
  if (num <= -108 && num >= -1131) {
    const uint8_t v = (-(num + 108) / 256) + 251;
    const uint8_t w = -(num + 108) % 256;
    out_bytes->push_back(v);
    out_bytes->push_back(w);
    return true;
  }
  if (num <= 32768 && num >= -32767) {
    const uint8_t v = (num % 0xff00u) >> 8;
    const uint8_t w = num % 0xffu;
    out_bytes->push_back(28);
    out_bytes->push_back(v);
    out_bytes->push_back(w);
    return true;
  }
  return false;
}

// Adds a subroutine |subr| to |out_buffer| and |out_subr|. The contents of the
// subroutine is copied to |out_buffer|, and then the position of the subroutine
// in |out_buffer| is written to |out_subr|. Returns true on success.
bool AddSubr(const int *subr, size_t subr_len,
             std::vector<uint8_t>* out_buffer, ots::CFFIndex *out_subr) {
  size_t pre_offset = out_buffer->size();
  for (size_t i = 0; i < subr_len; ++i) {
    if (subr[i] != kOpPrefix) {
      if (!EncodeNumber(subr[i], out_buffer)) {
        return false;
      }
    } else {
      if (i + 1 == subr_len) {
        return false;
      }
      ++i;
      if (!EncodeOperator(subr[i], out_buffer)) {
        return false;
      }
    }
  }

  ++(out_subr->count);
  out_subr->off_size = 1;
  if (out_subr->offsets.empty()) {
    out_subr->offsets.push_back(pre_offset);
  }
  out_subr->offsets.push_back(out_buffer->size());
  return true;
}

// Validates |char_string| and returns true if it's valid.
bool Validate(const int *char_string, size_t char_string_len,
              const int *global_subrs, size_t global_subrs_len,
              const int *local_subrs, size_t local_subrs_len) {
  std::vector<uint8_t> buffer;
  ots::CFFIndex* char_strings_index = new ots::CFFIndex;
  ots::CFFIndex global_subrs_index;
  ots::CFFIndex* local_subrs_index = new ots::CFFIndex;

  if (char_string) {
    if (!AddSubr(char_string, char_string_len,
                 &buffer, char_strings_index)) {
      return false;
    }
  }
  if (global_subrs) {
    if (!AddSubr(global_subrs, global_subrs_len,
                 &buffer, &global_subrs_index)) {
      return false;
    }
  }
  if (local_subrs) {
    if (!AddSubr(local_subrs, local_subrs_len,
                 &buffer, local_subrs_index)) {
      return false;
    }
  }

  ots::Buffer ots_buffer(&buffer[0], buffer.size());

  ots::FontFile* file = new ots::FontFile();
  file->context = new ots::OTSContext();
  ots::Font* font = new ots::Font(file);
  ots::OpenTypeCFF* cff = new ots::OpenTypeCFF(font, OTS_TAG_CFF);
  cff->charstrings_index = char_strings_index;
  cff->local_subrs = local_subrs_index;
  bool ret = ots::ValidateCFFCharStrings(*cff,
                                         global_subrs_index,
                                         &ots_buffer);
  delete file->context;
  delete file;
  delete font;
  delete cff;

  return ret;
}

// Validates |char_string| and returns true if it's valid.
bool ValidateCharStrings(const int *char_string, size_t char_string_len) {
  return Validate(char_string, char_string_len, NULL, 0, NULL, 0);
}

}  // namespace

TEST(ValidateTest, TestRMoveTo) {
  {
    const int char_string[] = {
      1, 2, kOpPrefix, ots::kRMoveTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1,  // width
      1, 2, kOpPrefix, ots::kRMoveTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, kOpPrefix, ots::kRMoveTo,
      1, 2, 3, kOpPrefix, ots::kRMoveTo,  // invalid number of args
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestHMoveTo) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kHMoveTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1,  // width
      1, kOpPrefix, ots::kHMoveTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kHMoveTo,
      1, 2, kOpPrefix, ots::kHMoveTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestVMoveTo) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1,  // width
      1, kOpPrefix, ots::kVMoveTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, kOpPrefix, ots::kVMoveTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestRLineTo) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, kOpPrefix, ots::kRLineTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, kOpPrefix, ots::kRLineTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, kOpPrefix, ots::kRLineTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, kOpPrefix, ots::kRLineTo,  // can't be the first op.
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestHLineTo) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, kOpPrefix, ots::kHLineTo,
      1, 2, kOpPrefix, ots::kHLineTo,
      1, 2, 3, kOpPrefix, ots::kHLineTo,
      1, 2, 3, 4, kOpPrefix, ots::kHLineTo,
      1, 2, 3, 4, 5, kOpPrefix, ots::kHLineTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      kOpPrefix, ots::kHLineTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kHLineTo,  // can't be the first op.
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestVLineTo) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, kOpPrefix, ots::kVLineTo,
      1, 2, kOpPrefix, ots::kVLineTo,
      1, 2, 3, kOpPrefix, ots::kVLineTo,
      1, 2, 3, 4, kOpPrefix, ots::kVLineTo,
      1, 2, 3, 4, 5, kOpPrefix, ots::kVLineTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      kOpPrefix, ots::kVLineTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVLineTo,  // can't be the first op.
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestRRCurveTo) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, 6, kOpPrefix, ots::kRRCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, kOpPrefix, ots::kRRCurveTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      kOpPrefix, ots::kRRCurveTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, 5, 6, kOpPrefix, ots::kRRCurveTo,  // can't be the first op.
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestHHCurveTo) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, kOpPrefix, ots::kHHCurveTo,
      1, 2, 3, 4, 5, kOpPrefix, ots::kHHCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, kOpPrefix, ots::kHHCurveTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, kOpPrefix, ots::kHHCurveTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, kOpPrefix, ots::kHHCurveTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, 5, kOpPrefix, ots::kHHCurveTo,  // can't be the first op.
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestHVCurveTo) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      // The first form.
      1, 2, 3, 4, kOpPrefix, ots::kHVCurveTo,
      1, 2, 3, 4, 5, kOpPrefix, ots::kHVCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, kOpPrefix, ots::kHVCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
      kOpPrefix, ots::kHVCurveTo,
      // The second form.
      1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kHVCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, kOpPrefix, ots::kHVCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
      kOpPrefix, ots::kHVCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
      22, 23, 24, 25, kOpPrefix, ots::kHVCurveTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, kOpPrefix, ots::kHVCurveTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, kOpPrefix, ots::kHVCurveTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, kOpPrefix, ots::kHVCurveTo,  // can't be the first op.
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestRCurveLine) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kRCurveLine,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
      kOpPrefix, ots::kRCurveLine,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, 6, 7, kOpPrefix, ots::kRCurveLine,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      // can't be the first op.
      1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kRCurveLine,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestRLineCurve) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kRLineCurve,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, kOpPrefix, ots::kRLineCurve,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, 6, 7, kOpPrefix, ots::kRLineCurve,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      // can't be the first op.
      1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kRLineCurve,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestVHCurveTo) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      // The first form.
      1, 2, 3, 4, kOpPrefix, ots::kVHCurveTo,
      1, 2, 3, 4, 5, kOpPrefix, ots::kVHCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, kOpPrefix, ots::kVHCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
      kOpPrefix, ots::kVHCurveTo,
      // The second form.
      1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kVHCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, kOpPrefix, ots::kVHCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
      kOpPrefix, ots::kVHCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
      22, 23, 24, 25, kOpPrefix, ots::kVHCurveTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, kOpPrefix, ots::kVHCurveTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, kOpPrefix, ots::kVHCurveTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, kOpPrefix, ots::kVHCurveTo,  // can't be the first op.
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestVVCurveTo) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, kOpPrefix, ots::kVVCurveTo,
      1, 2, 3, 4, 5, kOpPrefix, ots::kVVCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kVVCurveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, kOpPrefix, ots::kVVCurveTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      kOpPrefix, ots::kVVCurveTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, kOpPrefix, ots::kVVCurveTo,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, kOpPrefix, ots::kVVCurveTo,  // can't be the first op.
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestFlex) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, kOpPrefix, ots::kFlex,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      kOpPrefix, ots::kFlex,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, kOpPrefix, ots::kFlex,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, kOpPrefix, ots::kFlex,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestHFlex) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, 6, 7, kOpPrefix, ots::kHFlex,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      kOpPrefix, ots::kHFlex,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, 6, kOpPrefix, ots::kHFlex,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, 5, 6, 7, kOpPrefix, ots::kHFlex,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestHFlex1) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, kOpPrefix, ots::kHFlex1,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      kOpPrefix, ots::kHFlex1,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kHFlex1,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, 5, 6, 7, 8, 9, kOpPrefix, ots::kHFlex1,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestFlex1) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, kOpPrefix, ots::kFlex1,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      kOpPrefix, ots::kFlex1,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, kOpPrefix, ots::kFlex1,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, kOpPrefix, ots::kFlex1,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestEndChar) {
  {
    const int char_string[] = {
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
    };
    const int local_subrs[] = {
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(Validate(char_string, ARRAYSIZE(char_string),
                         NULL, 0,
                         local_subrs, ARRAYSIZE(local_subrs)));
  }
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallGSubr,
    };
    const int global_subrs[] = {
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(Validate(char_string, ARRAYSIZE(char_string),
                         global_subrs, ARRAYSIZE(global_subrs),
                         NULL, 0));
  }
}

TEST(ValidateTest, TestHStem) {
  {
    const int char_string[] = {
      1, 2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      0,  // width
      1, 2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      0, 1, 2, kOpPrefix, ots::kHStem,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, kOpPrefix, ots::kHStem,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestVStem) {
  {
    const int char_string[] = {
      1, 2, kOpPrefix, ots::kVStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, kOpPrefix, ots::kVStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      0,  // width
      1, 2, kOpPrefix, ots::kVStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      0, 1, 2, kOpPrefix, ots::kVStem,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, kOpPrefix, ots::kVStem,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestHStemHm) {
  {
    const int char_string[] = {
      1, 2, kOpPrefix, ots::kHStemHm,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, kOpPrefix, ots::kHStemHm,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      0,  // width
      1, 2, kOpPrefix, ots::kHStemHm,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      0, 1, 2, kOpPrefix, ots::kHStemHm,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, kOpPrefix, ots::kHStemHm,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestVStemHm) {
  {
    const int char_string[] = {
      1, 2, kOpPrefix, ots::kVStemHm,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, kOpPrefix, ots::kVStemHm,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      0,  // width
      1, 2, kOpPrefix, ots::kVStemHm,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      0, 1, 2, kOpPrefix, ots::kVStemHm,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kVMoveTo,
      1, 2, 3, 4, 5, kOpPrefix, ots::kVStemHm,  // invalid
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestHintMask) {
  {
    const int char_string[] = {
      1, 2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kHintMask, 0x00,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, kOpPrefix, ots::kHStem,
      3, 4, 5, 6, kOpPrefix, ots::kHintMask, 0x00,  // vstem
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      kOpPrefix, ots::kHintMask, 0x00,  // no stems to mask
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, kOpPrefix, ots::kHStem,
      3, 4, 5, kOpPrefix, ots::kHintMask, 0x00,  // invalid vstem
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestCntrMask) {
  {
    const int char_string[] = {
      1, 2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kCntrMask, 0x00,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, kOpPrefix, ots::kHStem,
      3, 4, 5, 6, kOpPrefix, ots::kCntrMask, 0x00,  // vstem
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      kOpPrefix, ots::kCntrMask, 0x00,  // no stems to mask
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, kOpPrefix, ots::kHStem,
      3, 4, 5, kOpPrefix, ots::kCntrMask, 0x00,  // invalid vstem
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestAbs) {
  {
    const int char_string[] = {
      -1, kOpPrefix, ots::kAbs,
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      kOpPrefix, ots::kAbs,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestAdd) {
  {
    const int char_string[] = {
      0, 1, kOpPrefix, ots::kAdd,
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kAdd,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestSub) {
  {
    const int char_string[] = {
      2, 1, kOpPrefix, ots::kSub,
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kSub,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestDiv) {
  // TODO(yusukes): Test div-by-zero.
  {
    const int char_string[] = {
      2, 1, kOpPrefix, ots::kDiv,
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kDiv,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestNeg) {
  {
    const int char_string[] = {
      -1, kOpPrefix, ots::kNeg,
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      kOpPrefix, ots::kNeg,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestRandom) {
  {
    const int char_string[] = {
      kOpPrefix, ots::kRandom,  // OTS rejects the operator.
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestMul) {
  {
    const int char_string[] = {
      2, 1, kOpPrefix, ots::kMul,
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kMul,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestSqrt) {
  // TODO(yusukes): Test negative numbers.
  {
    const int char_string[] = {
      4, kOpPrefix, ots::kSqrt,
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      kOpPrefix, ots::kSqrt,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestDrop) {
  {
    const int char_string[] = {
      1, 1, kOpPrefix, ots::kAdd,
      kOpPrefix, ots::kDrop,
      1, 2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      kOpPrefix, ots::kDrop,  // invalid
      1, 2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestExch) {
  {
    const int char_string[] = {
      1, 1, kOpPrefix, ots::kAdd,
      kOpPrefix, ots::kDup,
      kOpPrefix, ots::kExch,
      kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 1, kOpPrefix, ots::kAdd,
      kOpPrefix, ots::kExch,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestIndex) {
  {
    const int char_string[] = {
      1, 2, 3, -1, kOpPrefix, ots::kIndex,  // OTS rejects the operator.
      kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestRoll) {
  {
    const int char_string[] = {
      1, 2, 2, 1, kOpPrefix, ots::kRoll,  // OTS rejects the operator.
      kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestDup) {
  {
    const int char_string[] = {
      1, 1, kOpPrefix, ots::kAdd,
      kOpPrefix, ots::kDup,
      kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      kOpPrefix, ots::kDup,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestPut) {
  {
    const int char_string[] = {
      1, 10, kOpPrefix, ots::kPut,  // OTS rejects the operator.
      1, 2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestGet) {
  {
    const int char_string[] = {
      1, 10, kOpPrefix, ots::kGet,  // OTS rejects the operator.
      1, 2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestAnd) {
  {
    const int char_string[] = {
      2, 1, kOpPrefix, ots::kAnd,
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kAnd,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestOr) {
  {
    const int char_string[] = {
      2, 1, kOpPrefix, ots::kOr,
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kOr,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestNot) {
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kNot,
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      kOpPrefix, ots::kNot,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestEq) {
  {
    const int char_string[] = {
      2, 1, kOpPrefix, ots::kEq,
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, kOpPrefix, ots::kEq,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestIfElse) {
  {
    const int char_string[] = {
      1, 2, 3, 4, kOpPrefix, ots::kIfElse,
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, kOpPrefix, ots::kIfElse,  // invalid
      2, kOpPrefix, ots::kHStem,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestCallSubr) {
  // Call valid subr.
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
    };
    const int local_subrs[] = {
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(Validate(char_string, ARRAYSIZE(char_string),
                         NULL, 0,
                         local_subrs, ARRAYSIZE(local_subrs)));
  }
  // Call undefined subr.
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(-1), kOpPrefix, ots::kCallSubr,
    };
    const int local_subrs[] = {
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
                          NULL, 0,
                          local_subrs, ARRAYSIZE(local_subrs)));
  }
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(1), kOpPrefix, ots::kCallSubr,
    };
    const int local_subrs[] = {
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
                          NULL, 0,
                          local_subrs, ARRAYSIZE(local_subrs)));
  }
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(-1), kOpPrefix, ots::kCallSubr,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(1), kOpPrefix, ots::kCallSubr,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestCallGSubr) {
  // Call valid subr.
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallGSubr,
    };
    const int global_subrs[] = {
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(Validate(char_string, ARRAYSIZE(char_string),
                         global_subrs, ARRAYSIZE(global_subrs),
                         NULL, 0));
  }
  // Call undefined subr.
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(-1), kOpPrefix, ots::kCallGSubr,
    };
    const int global_subrs[] = {
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
                          global_subrs, ARRAYSIZE(global_subrs),
                          NULL, 0));
  }
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(1), kOpPrefix, ots::kCallGSubr,
    };
    const int global_subrs[] = {
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
                          global_subrs, ARRAYSIZE(global_subrs),
                          NULL, 0));
  }
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(-1), kOpPrefix, ots::kCallGSubr,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallGSubr,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(1), kOpPrefix, ots::kCallGSubr,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestCallGSubrWithComputedValues) {
  {
    // OTS does not allow to call(g)subr with a subroutine number which is
    // not a immediate value for safety.
    const int char_string[] = {
      0, 0, kOpPrefix, ots::kAdd,
      kOpPrefix, ots::kCallGSubr,
    };
    const int global_subrs[] = {
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
                          global_subrs, ARRAYSIZE(global_subrs),
                          NULL, 0));
  }
}

TEST(ValidateTest, TestInfiniteLoop) {
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
    };
    const int local_subrs[] = {
      GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
    };
    EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
                          NULL, 0,
                          local_subrs, ARRAYSIZE(local_subrs)));
  }
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallGSubr,
    };
    const int global_subrs[] = {
      GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallGSubr,
    };
    EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
                          global_subrs, ARRAYSIZE(global_subrs),
                          NULL, 0));
  }
  // mutual recursion which doesn't stop.
  {
    const int char_string[] = {
      GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
    };
    const int global_subrs[] = {
      GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
    };
    const int local_subrs[] = {
      GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallGSubr,
    };
    EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
                          global_subrs, ARRAYSIZE(global_subrs),
                          local_subrs, ARRAYSIZE(local_subrs)));
  }
}

TEST(ValidateTest, TestStackOverflow) {
  {
    const int char_string[] = {
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
      1, 2, 3, 4, 5, 6, 7, 8,
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
      1, 2, 3, 4, 5, 6, 7, 8, 9,  // overflow
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestDeprecatedOperators) {
  {
    const int char_string[] = {
      kOpPrefix, 16,  // 'blend'.
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      kOpPrefix, (12 << 8) + 8,  // 'store'.
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      kOpPrefix, (12 << 8) + 13,  // 'load'.
      kOpPrefix, ots::kEndChar,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

TEST(ValidateTest, TestUnterminatedCharString) {
  // No endchar operator.
  {
    const int char_string[] = {
      123,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      123, 456,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
  {
    const int char_string[] = {
      123, 456, kOpPrefix, ots::kReturn,
    };
    EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
  }
}

Messung V0.5
C=82 H=100 G=91

¤ Dauer der Verarbeitung: 0.12 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.