/*
 * Copyright (c) 2023, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 3-Clause Clear License
 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
 * License was not distributed with this source code in the LICENSE file, you
 * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
 * Alliance for Open Media Patent License 1.0 was not distributed with this
 * source code in the PATENTS file, you can obtain it at
 * www.aomedia.org/license/patent.
 */
#include "iamf/cli/wav_writer.h"

#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <numeric>
#include <string>
#include <utility>
#include <vector>

#include "absl/status/status_matchers.h"
#include "absl/types/span.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "iamf/cli/tests/cli_test_utils.h"
#include "iamf/obu/types.h"

using ::absl_testing::IsOk;

namespace iamf_tools {
namespace {

constexpr int kNumChannels = 1;
constexpr int kTwoChannels = 2;
constexpr int kSampleRateHz = 16000;
constexpr int kBitDepth16 = 16;
constexpr int kBitDepth24 = 24;
constexpr int kBitDepth32 = 32;
constexpr size_t kMaxInputSamplesPerFrame = 960;

constexpr InternalSampleType kSampleValue = 0.1;

TEST(WavWriterTest, Construct16BitWavWriter) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth16, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);
  EXPECT_EQ(wav_writer->bit_depth(), kBitDepth16);
}

TEST(WavWriterTest, Construct16BitWavWriterWithoutHeader) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth16, kMaxInputSamplesPerFrame,
                        /*write_header=*/false);
  ASSERT_NE(wav_writer, nullptr);
  EXPECT_EQ(wav_writer->bit_depth(), kBitDepth16);
}

TEST(WavWriterTest, Construct24BitWavWriter) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth24, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);
  EXPECT_EQ(wav_writer->bit_depth(), kBitDepth24);
}

TEST(WavWriterTest, Construct32BitWavWriter) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth32, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);
  EXPECT_EQ(wav_writer->bit_depth(), kBitDepth32);
}

TEST(WavWriterTest, InvalidBitDepthFailsAtCreation) {
  const int kInvalidBitDepth = 13;
  auto wav_writer = WavWriter::Create(
      GetAndCleanupOutputFileName(".wav"), kNumChannels, kSampleRateHz,
      kInvalidBitDepth, kMaxInputSamplesPerFrame);
  EXPECT_EQ(wav_writer, nullptr);
}

TEST(DeprecatedWritePcmSamples, WriteEmptySamplesSucceeds) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth24, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);

  const std::vector<uint8_t> kEmptySamples;
  EXPECT_THAT(wav_writer->WritePcmSamples(kEmptySamples), IsOk());
}

TEST(PushFrame, WriteChannelsOfEmptySamplesSucceeds) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth24, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);

  const std::vector<std::vector<int32_t>> kChannelsOfEmptySamplesInt(
      kNumChannels, std::vector<int32_t>());
  const auto kChannelsOfEmptySamples =
      Int32ToInternalSampleType2D(kChannelsOfEmptySamplesInt);
  EXPECT_THAT(
      wav_writer->PushFrame(MakeSpanOfConstSpans(kChannelsOfEmptySamples)),
      IsOk());
}

TEST(DeprecatedWritePcmSamples, WriteIntegerSamplesSucceeds) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth16, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);

  // Bit depth = 16, and writing 6 bytes = 48 bits = 3 samples succeeds.
  std::vector<uint8_t> samples(6, 0);
  EXPECT_THAT(wav_writer->WritePcmSamples(samples), IsOk());
}

TEST(PushFrame, WriteIntegerSamplesSucceeds) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth16, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);

  constexpr int kNumSamples = 3;
  const std::vector<std::vector<InternalSampleType>> samples(
      kNumChannels, std::vector<InternalSampleType>(kNumSamples, kSampleValue));
  EXPECT_THAT(wav_writer->PushFrame(MakeSpanOfConstSpans(samples)), IsOk());
}

TEST(PushFrame, WriteManyChannelsSucceeds) {
  // The wav writer samples supports many channels. For example, it could
  // represent a 9.1.6 channel layout using 16 channels.
  constexpr int kNumChannels = 16;
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth16, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);

  constexpr int kNumSamples = 3;
  const std::vector<std::vector<InternalSampleType>> samples(
      kNumChannels, std::vector<InternalSampleType>(kNumSamples, kSampleValue));
  EXPECT_THAT(wav_writer->PushFrame(MakeSpanOfConstSpans(samples)), IsOk());
}

TEST(DeprecatedWritePcmSamples, WriteMoreSamplesThanConfiguredFails) {
  constexpr size_t kMaxOneInputSample = 1;
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth16, kMaxOneInputSample);
  ASSERT_NE(wav_writer, nullptr);

  // Bit depth = 16, and writing 4 bytes = 32 bits = 2 samples fails.
  std::vector<uint8_t> samples(4, 0);
  EXPECT_FALSE(wav_writer->WritePcmSamples(samples).ok());
}

TEST(PushFrame, WriteMoreSamplesThanConfiguredFails) {
  constexpr size_t kMaxOneInputSample = 1;
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth16, kMaxOneInputSample);
  ASSERT_NE(wav_writer, nullptr);

  constexpr int kTooManySamples = 2;
  const std::vector<std::vector<InternalSampleType>> samples(
      kNumChannels,
      std::vector<InternalSampleType>(kTooManySamples, kSampleValue));
  EXPECT_FALSE(wav_writer->PushFrame(MakeSpanOfConstSpans(samples)).ok());
}

TEST(DeprecatedWritePcmSamples, DeprecatedWriteNonIntegerNumberOfSamplesFails) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth16, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);

  // Bit depth = 16, and writing 3 bytes = 24 bits = 1.5 samples fails.
  std::vector<uint8_t> samples(3, 0);
  EXPECT_FALSE(wav_writer->WritePcmSamples(samples).ok());
}

TEST(PushFrame, WriteChannelWithTooFewSamplesFails) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kTwoChannels,
                        kSampleRateHz, kBitDepth16, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);

  // The second tick is missing a channel.
  const std::vector<std::vector<InternalSampleType>> samples = {
      {kSampleValue, kSampleValue}, {kSampleValue}};
  EXPECT_FALSE(wav_writer->PushFrame(MakeSpanOfConstSpans(samples)).ok());
}

TEST(PushFrame, ConsumesInputSamples) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth16, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);
  constexpr int kNumSamples = 3;
  const std::vector<std::vector<InternalSampleType>> samples(
      kNumChannels, std::vector<InternalSampleType>(kNumSamples, kSampleValue));

  EXPECT_THAT(wav_writer->PushFrame(MakeSpanOfConstSpans(samples)), IsOk());

  // The writer consumes all input samples, so
  // `SampleProcessorBase::GetOutputSamplesAsSpan` will always return a span of
  // empty spans.
  for (const auto channel_span : wav_writer->GetOutputSamplesAsSpan()) {
    EXPECT_TRUE(channel_span.empty());
  }
}

TEST(DeprecatedWritePcmSamples,
     DeprecatedWriteIntegerSamplesSucceedsWithoutHeader) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth16, kMaxInputSamplesPerFrame,
                        /*write_header=*/false);
  ASSERT_NE(wav_writer, nullptr);

  // Bit depth = 16, and writing 6 bytes = 48 bits = 3 samples succeeds.
  std::vector<uint8_t> samples(6, 0);
  EXPECT_THAT(wav_writer->WritePcmSamples(samples), IsOk());
}

TEST(DeprecatedWritePcmSamples, DeprecatedWrite24BitSamplesSucceeds) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth24, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);

  // Bit depth = 24, and writing 6 bytes = 48 bits = 2 samples succeeds.
  std::vector<uint8_t> samples(6, 0);
  EXPECT_THAT(wav_writer->WritePcmSamples(samples), IsOk());
}

TEST(DeprecatedWritePcmSamples, DeprecatedWrite32BitSamplesSucceeds) {
  auto wav_writer =
      WavWriter::Create(GetAndCleanupOutputFileName(".wav"), kNumChannels,
                        kSampleRateHz, kBitDepth32, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);

  // Bit depth = 32, and writing 8 bytes = 64 bits = 2 samples succeeds.
  std::vector<uint8_t> samples = {1, 0, 0, 0, 2, 0, 0, 0};
  EXPECT_THAT(wav_writer->WritePcmSamples(samples), IsOk());
}

TEST(DeprecatedWritePcmSamples, FileExistsAndHasNonZeroSizeWithHeader) {
  const std::filesystem::path output_file_path(
      GetAndCleanupOutputFileName(".wav"));
  {
    // Create the writer in a small scope. It should be destroyed before
    // checking the results.
    auto wav_writer =
        WavWriter::Create(output_file_path.string(), kNumChannels,
                          kSampleRateHz, kBitDepth16, kMaxInputSamplesPerFrame);
  }

  EXPECT_TRUE(std::filesystem::exists(output_file_path));
  std::error_code error_code;
  EXPECT_NE(std::filesystem::file_size(output_file_path, error_code), 0);
  EXPECT_FALSE(error_code);
}

TEST(WavWriterTest, EmptyFileExistsAndHasZeroSizeWithoutHeader) {
  const std::filesystem::path output_file_path(
      GetAndCleanupOutputFileName(".wav"));
  {
    // Create the writer in a small scope. It should be destroyed before
    // checking the results.
    auto wav_writer =
        WavWriter::Create(output_file_path.string(), kNumChannels,
                          kSampleRateHz, kBitDepth16, kMaxInputSamplesPerFrame,
                          /*write_header=*/false);
  }

  EXPECT_TRUE(std::filesystem::exists(output_file_path));

  std::error_code error_code;
  EXPECT_EQ(std::filesystem::file_size(output_file_path, error_code), 0)
      << output_file_path;
  EXPECT_FALSE(error_code);
}

TEST(WavWriterTest, OutputFileHasCorrectSizeWithoutHeader) {
  const std::filesystem::path output_file_path(
      GetAndCleanupOutputFileName(".wav"));
  const int kInputBytes = 10;
  {
    // Create the writer in a small scope. It should be destroyed before
    // checking the results.
    auto wav_writer =
        WavWriter::Create(output_file_path.string(), kNumChannels,
                          kSampleRateHz, kBitDepth16, kMaxInputSamplesPerFrame,
                          /*write_header=*/false);
    ASSERT_NE(wav_writer, nullptr);
    std::vector<uint8_t> samples(kInputBytes, 0);
    EXPECT_THAT(wav_writer->WritePcmSamples(samples), IsOk());
  }

  std::error_code error_code;
  EXPECT_EQ(std::filesystem::file_size(output_file_path, error_code),
            kInputBytes);
  EXPECT_FALSE(error_code);
}

TEST(WavWriterTest,
     Output16BitWavFileHasCorrectDataWithDeprecatedWritePcmSamples) {
  const std::string output_file_path(GetAndCleanupOutputFileName(".wav"));
  const std::vector<std::vector<int32_t>> kExpectedSamples = {
      {0x01000000, 0x03020000, 0x05040000, 0x07060000, 0x09080000, 0x0b0a0000}};
  constexpr int kNumSamplesPerFrame = 6;
  const int kInputBytes = kNumSamplesPerFrame * 2;
  {
    // Create the writer in a small scope. It should be destroyed before
    // checking the results.
    auto wav_writer =
        WavWriter::Create(output_file_path, kNumChannels, kSampleRateHz,
                          kBitDepth16, kMaxInputSamplesPerFrame);
    ASSERT_NE(wav_writer, nullptr);
    std::vector<uint8_t> samples(kInputBytes, 0);
    std::iota(samples.begin(), samples.end(), 0);
    EXPECT_THAT(wav_writer->WritePcmSamples(samples), IsOk());
  }

  auto wav_reader =
      CreateWavReaderExpectOk(output_file_path, kNumSamplesPerFrame);
  EXPECT_EQ(wav_reader.remaining_samples(), kNumSamplesPerFrame);
  EXPECT_TRUE(wav_reader.ReadFrame());
  EXPECT_EQ(wav_reader.buffers_, kExpectedSamples);
}

TEST(WavWriterTest,
     Output16BitWavFileHasCorrectDataWithPushFrameAfterDestruction) {
  const std::string output_file_path(GetAndCleanupOutputFileName(".wav"));
  const std::vector<std::vector<int32_t>> kExpectedSamplesInt32 = {
      {0x01000000, 0x03020000, 0x05040000, 0x07060000, 0x09080000, 0x0b0a0000}};
  const auto kExpectedSamples =
      Int32ToInternalSampleType2D(kExpectedSamplesInt32);
  constexpr int kNumSamplesPerFrame = 6;
  {
    // Create the writer in a small scope. The user can safely omit the call the
    // `Flush()` method, but then they must wait until the writer is destroyed,
    // to read the finalized header.
    auto wav_writer =
        WavWriter::Create(output_file_path, kNumChannels, kSampleRateHz,
                          kBitDepth16, kMaxInputSamplesPerFrame);
    ASSERT_NE(wav_writer, nullptr);
    EXPECT_THAT(wav_writer->PushFrame(MakeSpanOfConstSpans(kExpectedSamples)),
                IsOk());
  }

  auto wav_reader =
      CreateWavReaderExpectOk(output_file_path, kNumSamplesPerFrame);
  EXPECT_EQ(wav_reader.remaining_samples(), kNumSamplesPerFrame);
  EXPECT_TRUE(wav_reader.ReadFrame());
  EXPECT_EQ(wav_reader.buffers_, kExpectedSamplesInt32);
}

TEST(WavWriterTest, Output16BitWavFileHasCorrectDataWithPushFrameAfterFlush) {
  const std::string output_file_path(GetAndCleanupOutputFileName(".wav"));
  const std::vector<std::vector<int32_t>> kExpectedSamplesInt32 = {
      {0x01000000, 0x03020000, 0x05040000, 0x07060000, 0x09080000, 0x0b0a0000}};
  const auto kExpectedSamples =
      Int32ToInternalSampleType2D(kExpectedSamplesInt32);
  constexpr int kNumSamplesPerFrame = 6;

  auto wav_writer =
      WavWriter::Create(output_file_path, kNumChannels, kSampleRateHz,
                        kBitDepth16, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);
  EXPECT_THAT(wav_writer->PushFrame(MakeSpanOfConstSpans(kExpectedSamples)),
              IsOk());
  // Instead of waiting for the destructor to call `Flush()`, the user can call
  // `Flush()` explicitly, to signal the wav header (including the total number
  // of samples) to be finalized.
  EXPECT_THAT(wav_writer->Flush(), IsOk());

  auto wav_reader =
      CreateWavReaderExpectOk(output_file_path, kNumSamplesPerFrame);
  EXPECT_EQ(wav_reader.remaining_samples(), kNumSamplesPerFrame);
  EXPECT_TRUE(wav_reader.ReadFrame());
  EXPECT_EQ(wav_reader.buffers_, kExpectedSamplesInt32);
}

TEST(WavWriterTest,
     Output24BitWavFileHasCorrectDataWithDeprecatedWritePcmSamples) {
  const std::string output_file_path(GetAndCleanupOutputFileName(".wav"));
  const std::vector<std::vector<int32_t>> kExpectedSamples = {
      {0x02010000, 0x05040300, 0x08070600, 0x0b0a0900}};
  constexpr int kNumSamplesPerFrame = 4;
  constexpr int kInputBytes = kNumSamplesPerFrame * 3;
  {
    // Create the writer in a small scope. It should be destroyed before
    // checking the results.
    auto wav_writer =
        WavWriter::Create(output_file_path, kNumChannels, kSampleRateHz,
                          kBitDepth24, kMaxInputSamplesPerFrame);
    ASSERT_NE(wav_writer, nullptr);
    std::vector<uint8_t> samples(kInputBytes, 0);
    std::iota(samples.begin(), samples.end(), 0);
    EXPECT_THAT(wav_writer->WritePcmSamples(samples), IsOk());
  }

  auto wav_reader =
      CreateWavReaderExpectOk(output_file_path, kNumSamplesPerFrame);
  EXPECT_EQ(wav_reader.remaining_samples(), kNumSamplesPerFrame);
  EXPECT_TRUE(wav_reader.ReadFrame());
  EXPECT_EQ(wav_reader.buffers_, kExpectedSamples);
}

TEST(WavWriterTest, Output24BitWavFileHasCorrectData) {
  const std::string output_file_path(GetAndCleanupOutputFileName(".wav"));
  const std::vector<std::vector<int32_t>> kExpectedSamplesInt32 = {
      {0x02010000, 0x05040300, 0x08070600, 0x0b0a0900}};
  const auto kExpectedSamples =
      Int32ToInternalSampleType2D(kExpectedSamplesInt32);
  constexpr int kNumSamplesPerFrame = 4;
  {
    // Create the writer in a small scope. It should be destroyed before
    // checking the results.
    auto wav_writer =
        WavWriter::Create(output_file_path, kNumChannels, kSampleRateHz,
                          kBitDepth24, kMaxInputSamplesPerFrame);
    EXPECT_THAT(wav_writer->PushFrame(MakeSpanOfConstSpans(kExpectedSamples)),
                IsOk());
  }

  auto wav_reader =
      CreateWavReaderExpectOk(output_file_path, kNumSamplesPerFrame);
  EXPECT_EQ(wav_reader.remaining_samples(), kNumSamplesPerFrame);
  EXPECT_TRUE(wav_reader.ReadFrame());
  EXPECT_EQ(wav_reader.buffers_, kExpectedSamplesInt32);
}

TEST(WavWriterTest,
     Output32BitWavFileHasCorrectDataWithDeprecatedWritePcmSamples) {
  const std::string output_file_path(GetAndCleanupOutputFileName(".wav"));
  const std::vector<std::vector<int32_t>> kExpectedSamples = {
      {0x03020100, 0x07060504, 0x0b0a0908}};
  constexpr int kNumSamplesPerFrame = 3;
  constexpr int kInputBytes = kNumSamplesPerFrame * 4;
  {
    // Create the writer in a small scope. It should be destroyed before
    // checking the results.
    auto wav_writer =
        WavWriter::Create(output_file_path, kNumChannels, kSampleRateHz,
                          kBitDepth32, kMaxInputSamplesPerFrame);
    ASSERT_NE(wav_writer, nullptr);
    std::vector<uint8_t> samples(kInputBytes, 0);
    std::iota(samples.begin(), samples.end(), 0);
    EXPECT_THAT(wav_writer->WritePcmSamples(samples), IsOk());
  }

  auto wav_reader =
      CreateWavReaderExpectOk(output_file_path, kNumSamplesPerFrame);
  EXPECT_EQ(wav_reader.remaining_samples(), 3);
  EXPECT_TRUE(wav_reader.ReadFrame());
  EXPECT_EQ(wav_reader.buffers_, kExpectedSamples);
}

TEST(WavWriterTest, Output32BitWavFileHasCorrectData) {
  const std::string output_file_path(GetAndCleanupOutputFileName(".wav"));
  const std::vector<std::vector<int32_t>> kExpectedSamplesInt32 = {
      {0x03020100, 0x07060504, 0x0b0a0908}};
  const auto kExpectedSamples =
      Int32ToInternalSampleType2D(kExpectedSamplesInt32);
  constexpr int kNumSamplesPerFrame = 3;
  {
    // Create the writer in a small scope. It should be destroyed before
    // checking the results.
    auto wav_writer =
        WavWriter::Create(output_file_path, kNumChannels, kSampleRateHz,
                          kBitDepth32, kMaxInputSamplesPerFrame);
    ASSERT_NE(wav_writer, nullptr);
    EXPECT_THAT(wav_writer->PushFrame(MakeSpanOfConstSpans(kExpectedSamples)),
                IsOk());
  }

  auto wav_reader =
      CreateWavReaderExpectOk(output_file_path, kNumSamplesPerFrame);
  EXPECT_EQ(wav_reader.remaining_samples(), 3);
  EXPECT_TRUE(wav_reader.ReadFrame());
  EXPECT_EQ(wav_reader.buffers_, kExpectedSamplesInt32);
}

TEST(WavWriterTest, OutputWithManyChannelsHasCorrectData) {
  constexpr int kNumChannels = 6;
  const std::string output_file_path(GetAndCleanupOutputFileName(".wav"));
  const std::vector<std::vector<int32_t>> kExpectedSamplesInt32 = {
      {0x01010101, 0x01020202}, {0x02010101, 0x02020202},
      {0x03010101, 0x03020202}, {0x04010101, 0x04020202},
      {0x05010101, 0x05020202}, {0x06010101, 0x06020202}};
  const auto kExpectedSamples =
      Int32ToInternalSampleType2D(kExpectedSamplesInt32);

  constexpr int kNumSamplesPerFrame = 2;
  {
    // Create the writer in a small scope. It should be destroyed before
    // checking the results.
    auto wav_writer =
        WavWriter::Create(output_file_path, kNumChannels, kSampleRateHz,
                          kBitDepth32, kMaxInputSamplesPerFrame);
    ASSERT_NE(wav_writer, nullptr);
    EXPECT_THAT(wav_writer->PushFrame(MakeSpanOfConstSpans(kExpectedSamples)),
                IsOk());
  }

  auto wav_reader =
      CreateWavReaderExpectOk(output_file_path, kNumSamplesPerFrame);
  EXPECT_EQ(wav_reader.remaining_samples(), 12);
  EXPECT_TRUE(wav_reader.ReadFrame());
  EXPECT_EQ(wav_reader.buffers_, kExpectedSamplesInt32);
}

TEST(WavWriterTest, OutputWavFileHasCorrectProperties) {
  const std::string output_file_path(GetAndCleanupOutputFileName(".wav"));
  {
    // Create the writer in a small scope. It should be destroyed before
    // checking the results.
    auto wav_writer =
        WavWriter::Create(output_file_path, kNumChannels, kSampleRateHz,
                          kBitDepth32, kMaxInputSamplesPerFrame);
    ASSERT_NE(wav_writer, nullptr);
  }

  auto wav_reader = CreateWavReaderExpectOk(output_file_path);
  EXPECT_EQ(wav_reader.sample_rate_hz(), kSampleRateHz);
  EXPECT_EQ(wav_reader.num_channels(), kNumChannels);
  EXPECT_EQ(wav_reader.bit_depth(), kBitDepth32);
}

TEST(WavWriterTest, OutputWavFileHasCorrectPropertiesAfterMoving) {
  const std::string output_file_path(GetAndCleanupOutputFileName(".wav"));
  {
    auto wav_writer =
        WavWriter::Create(output_file_path, kNumChannels, kSampleRateHz,
                          kBitDepth32, kMaxInputSamplesPerFrame);
    ASSERT_NE(wav_writer, nullptr);

    // Create the writer in a small scope. It should be destroyed before
    // checking the results.
    auto new_wav_writer = std::move(wav_writer);
    ASSERT_NE(new_wav_writer, nullptr);
  }

  const auto wav_reader = CreateWavReaderExpectOk(output_file_path);
  EXPECT_EQ(wav_reader.sample_rate_hz(), kSampleRateHz);
  EXPECT_EQ(wav_reader.num_channels(), kNumChannels);
  EXPECT_EQ(wav_reader.bit_depth(), kBitDepth32);
}

TEST(WavWriterTest, AbortDeletesOutputFile) {
  const std::string output_file_path(GetAndCleanupOutputFileName(".wav"));
  auto wav_writer =
      WavWriter::Create(output_file_path, kNumChannels, kSampleRateHz,
                        kBitDepth16, kMaxInputSamplesPerFrame);
  ASSERT_NE(wav_writer, nullptr);
  wav_writer->Abort();

  // Expect that the output file is deleted.
  EXPECT_FALSE(
      std::filesystem::exists(std::filesystem::path(output_file_path)));
}

}  // namespace
}  // namespace iamf_tools
