blob: eab8e9af611abb5091d44e53d38bfdc2765162ac [file]
// Copyright 2026 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "iree/tokenizer/normalizer/passthrough.h"
#include "iree/base/api.h"
#include "iree/testing/gtest.h"
#include "iree/testing/status_matchers.h"
#include "iree/tokenizer/normalizer/normalizer_test_util.h"
namespace iree::tokenizer {
namespace {
using testing::ProcessAndFinalize;
using testing::ScopedNormalizer;
using testing::ScopedNormalizerState;
using testing::TestLimitedOutputCapacity;
using testing::TestWithAllChunkSizes;
using testing::TestZeroCapacityOutput;
//===----------------------------------------------------------------------===//
// Test fixture for passthrough normalizer tests.
//===----------------------------------------------------------------------===//
class PassthroughNormalizerTest : public ::testing::Test {
protected:
void SetUp() override {
iree_tokenizer_normalizer_t* raw_normalizer = nullptr;
IREE_ASSERT_OK(iree_tokenizer_normalizer_passthrough_allocate(
iree_allocator_system(), &raw_normalizer));
normalizer_ = ScopedNormalizer(raw_normalizer);
}
iree_tokenizer_normalizer_t* normalizer() { return normalizer_.get(); }
private:
ScopedNormalizer normalizer_;
};
//===----------------------------------------------------------------------===//
// Lifecycle
//===----------------------------------------------------------------------===//
TEST_F(PassthroughNormalizerTest, CreateAndDestroy) {
// SetUp/TearDown handles lifecycle. Verify normalizer was created.
EXPECT_NE(normalizer(), nullptr);
}
TEST_F(PassthroughNormalizerTest, StateSizeIsReasonable) {
iree_host_size_t state_size =
iree_tokenizer_normalizer_state_size(normalizer());
EXPECT_GT(state_size, 0u);
// Passthrough state should be minimal (just the base struct).
EXPECT_LE(state_size, 64u);
}
//===----------------------------------------------------------------------===//
// No-ops
//===----------------------------------------------------------------------===//
TEST_F(PassthroughNormalizerTest, EmptyInput) {
std::string result = ProcessAndFinalize(
normalizer(), "", /*expect_pending_after_process=*/false);
EXPECT_TRUE(result.empty());
}
TEST_F(PassthroughNormalizerTest, ZeroCapacityOutput) {
TestZeroCapacityOutput(normalizer(), "Hello, World!");
}
//===----------------------------------------------------------------------===//
// Edge Cases
//===----------------------------------------------------------------------===//
TEST_F(PassthroughNormalizerTest, SingleChar) {
TestWithAllChunkSizes(normalizer(), "a", "a",
/*expect_pending_after_process=*/false);
}
//===----------------------------------------------------------------------===//
// Basic Functionality
//===----------------------------------------------------------------------===//
TEST_F(PassthroughNormalizerTest, ProcessCopiesInputToOutput) {
TestWithAllChunkSizes(normalizer(), "Hello, World!", "Hello, World!",
/*expect_pending_after_process=*/false);
}
TEST_F(PassthroughNormalizerTest, UnicodeContentPassedThrough) {
// Passthrough should handle UTF-8 content without modification.
TestWithAllChunkSizes(normalizer(), "こんにちは世界", "こんにちは世界",
/*expect_pending_after_process=*/false);
}
TEST_F(PassthroughNormalizerTest, MixedContent) {
// Mixed ASCII, UTF-8, and special characters.
TestWithAllChunkSizes(normalizer(), "Hello 世界! 🌍", "Hello 世界! 🌍",
/*expect_pending_after_process=*/false);
}
//===----------------------------------------------------------------------===//
// Streaming Behavior
//===----------------------------------------------------------------------===//
TEST_F(PassthroughNormalizerTest, HasPendingAlwaysFalse) {
ScopedNormalizerState state(normalizer());
EXPECT_FALSE(iree_tokenizer_normalizer_state_has_pending(state.get()));
// Even after processing.
char output[64];
iree_host_size_t consumed = 0;
iree_host_size_t written = 0;
IREE_ASSERT_OK(iree_tokenizer_normalizer_state_process(
state.get(), iree_make_cstring_view("Hello"),
iree_make_mutable_string_view(output, sizeof(output)),
IREE_TOKENIZER_NORMALIZER_FLAG_NONE, &consumed, &written));
EXPECT_FALSE(iree_tokenizer_normalizer_state_has_pending(state.get()));
}
TEST_F(PassthroughNormalizerTest, FinalizeProducesNothing) {
ScopedNormalizerState state(normalizer());
char output[64];
iree_host_size_t written = 0;
IREE_ASSERT_OK(iree_tokenizer_normalizer_state_finalize(
state.get(), iree_make_mutable_string_view(output, sizeof(output)),
&written));
// Passthrough never buffers, so finalize produces nothing.
EXPECT_EQ(written, 0u);
}
//===----------------------------------------------------------------------===//
// Output Buffer Handling
//===----------------------------------------------------------------------===//
TEST_F(PassthroughNormalizerTest, LimitedOutputCapacity) {
TestLimitedOutputCapacity(normalizer(), "Hello, World!", "Hello, World!");
}
TEST_F(PassthroughNormalizerTest, ProcessRespectsOutputCapacity) {
ScopedNormalizerState state(normalizer());
const char* input = "Hello, World!";
char output[5]; // Smaller than input.
iree_host_size_t consumed = 0;
iree_host_size_t written = 0;
IREE_ASSERT_OK(iree_tokenizer_normalizer_state_process(
state.get(), iree_make_cstring_view(input),
iree_make_mutable_string_view(output, 5),
IREE_TOKENIZER_NORMALIZER_FLAG_NONE, &consumed, &written));
// Should only consume/write what fits.
EXPECT_EQ(consumed, 5u);
EXPECT_EQ(written, 5u);
EXPECT_EQ(std::string(output, 5), "Hello");
}
} // namespace
} // namespace iree::tokenizer