// Copyright 2013 The Chromium 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 <vector>

#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/strings/string_piece.h"
#include "base/test/test_message_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "media/audio/audio_manager.h"
#include "media/audio/simple_sources.h"
#include "media/audio/sounds/audio_stream_handler.h"
#include "media/audio/sounds/sounds_manager.h"
#include "media/audio/sounds/test_data.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {

class SoundsManagerTest : public testing::Test {
 public:
  SoundsManagerTest() {}
  ~SoundsManagerTest() override {}

  void SetUp() override {
    audio_manager_ =
        AudioManager::CreateForTesting(base::ThreadTaskRunnerHandle::Get());
    SoundsManager::Create();
    base::RunLoop().RunUntilIdle();
  }

  void TearDown() override {
    SoundsManager::Shutdown();
    base::RunLoop().RunUntilIdle();
  }

  void SetObserverForTesting(AudioStreamHandler::TestObserver* observer) {
    AudioStreamHandler::SetObserverForTesting(observer);
  }

  void SetAudioSourceForTesting(
      AudioOutputStream::AudioSourceCallback* source) {
    AudioStreamHandler::SetAudioSourceForTesting(source);
  }

 private:
  base::TestMessageLoop message_loop_;
  ScopedAudioManagerPtr audio_manager_;
};

TEST_F(SoundsManagerTest, Play) {
  ASSERT_TRUE(SoundsManager::Get());

  base::RunLoop run_loop;
  TestObserver observer(run_loop.QuitClosure());

  SetObserverForTesting(&observer);

  ASSERT_TRUE(SoundsManager::Get()->Initialize(
      kTestAudioKey,
      base::StringPiece(kTestAudioData, arraysize(kTestAudioData))));
  ASSERT_EQ(20,
            SoundsManager::Get()->GetDuration(kTestAudioKey).InMicroseconds());
  ASSERT_TRUE(SoundsManager::Get()->Play(kTestAudioKey));
  run_loop.Run();

  ASSERT_EQ(1, observer.num_play_requests());
  ASSERT_EQ(1, observer.num_stop_requests());
  ASSERT_EQ(4, observer.cursor());

  SetObserverForTesting(NULL);
}

TEST_F(SoundsManagerTest, Stop) {
  ASSERT_TRUE(SoundsManager::Get());

  base::RunLoop run_loop;
  TestObserver observer(run_loop.QuitClosure());

  SetObserverForTesting(&observer);

  ASSERT_TRUE(SoundsManager::Get()->Initialize(
      kTestAudioKey,
      base::StringPiece(kTestAudioData, arraysize(kTestAudioData))));

  // This overrides the wav data set by kTestAudioData and results in
  // a never-ending sine wave being played.
  const int kChannels = 1;
  const double kFreq = 200;
  const double kSampleFreq = 44100;
  SineWaveAudioSource sine_source(kChannels, kFreq, kSampleFreq);
  SetAudioSourceForTesting(&sine_source);

  ASSERT_EQ(0, observer.num_play_requests());
  ASSERT_EQ(0, observer.num_stop_requests());

  ASSERT_TRUE(SoundsManager::Get()->Play(kTestAudioKey));
  ASSERT_TRUE(SoundsManager::Get()->Stop(kTestAudioKey));
  run_loop.Run();

  ASSERT_EQ(1, observer.num_play_requests());
  ASSERT_EQ(1, observer.num_stop_requests());

  SetObserverForTesting(NULL);
}

TEST_F(SoundsManagerTest, Uninitialized) {
  ASSERT_TRUE(SoundsManager::Get());
  ASSERT_FALSE(SoundsManager::Get()->Play(kTestAudioKey));
  ASSERT_FALSE(SoundsManager::Get()->Stop(kTestAudioKey));
}

}  // namespace media
