Refactor AudioStream methods to handle closed state
diff --git a/tests/testStreamClosedMethods.cpp b/tests/testStreamClosedMethods.cpp
index 6e88ad1..e148ee5 100644
--- a/tests/testStreamClosedMethods.cpp
+++ b/tests/testStreamClosedMethods.cpp
@@ -14,74 +14,308 @@
  * limitations under the License.
  */
 
+/*
+ * TODO:
+ Create test runner APK
+ Remove hardcoded ANDROID_NDK from cmake config
+ */
 
 #include <gtest/gtest.h>
-#include <oboe/Definitions.h>
-#include <oboe/Utilities.h>
-
-/**
- * Tests needing to be written:
- *
- * getChannelCount
- * getDirection
-getSampleRate
-getFramesPerCallback
-getFormat
-getBufferSizeInFrames
-getBufferCapacityInFrames
-getSharingMode
-getPerformanceMode
-getDeviceId
-getCallback
-getUsage
-getContentType
-getInputPreset
-getSessionId
-getState
-getXRunCount
-getFramesPerBurst
-isPlaying
-getBytesPerFrame
-getBytesPerSample
-getFramesWritten
-getFramesRead
-getTimestamp
-getAudioApi
-usesAAudio
-
-Stream state control
-open
-close
-start
-pause
-flush
-stop
-requestStart
-requestPause
-requestFlush
-requestStop
-waitForStateChange
-
-Setters
-setBufferSizeInFrames
-
-Helpers
-calculateLatencyMillis
-
-I/O
-write
-read
- */
+#include <oboe/Oboe.h>
 
 using namespace oboe;
 
+class MyCallback : public AudioStreamCallback {
+public:
+    DataCallbackResult onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) override {
+        return DataCallbackResult::Continue;
+    }
+};
+
+
+
 class StreamClosedReturnValues : public ::testing::Test {
 
+protected:
 
+    void SetUp(){
+
+    }
+
+    bool openStream(){
+        Result r = mBuilder.openStream(&mStream);
+        EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r);
+        return (r == Result::OK);
+    }
+
+    void closeStream(){
+        Result r = mStream->close();
+        if (r != Result::OK){
+            FAIL() << "Failed to close stream. " << convertToText(r);
+        }
+    }
+
+    void openAndCloseStream(){
+
+        openStream();
+        closeStream();
+        ASSERT_EQ(mStream->getState(), StreamState::Closed) << "Stream state " << convertToText(mStream->getState());
+    }
+
+    AudioStreamBuilder mBuilder;
+    AudioStream *mStream = nullptr;
 
 };
 
 TEST_F(StreamClosedReturnValues, GetChannelCountReturnsLastKnownValue){
 
-    FAIL();
-}
\ No newline at end of file
+    mBuilder.setChannelCount(2);
+    openAndCloseStream();
+    ASSERT_EQ(mStream->getChannelCount(), 2);
+}
+
+TEST_F(StreamClosedReturnValues, GetDirectionReturnsLastKnownValue){
+
+    // Note that when testing on the emulator setting the direction to Input will result in ErrorInternal when
+    // opening the stream
+    mBuilder.setDirection(Direction::Input);
+    openAndCloseStream();
+    ASSERT_EQ(mStream->getDirection(), Direction::Input);
+}
+
+TEST_F(StreamClosedReturnValues, GetSampleRateReturnsLastKnownValue){
+
+    mBuilder.setSampleRate(8000);
+    openAndCloseStream();
+    ASSERT_EQ(mStream->getSampleRate(), 8000);
+}
+
+TEST_F(StreamClosedReturnValues, GetFramesPerCallbackReturnsLastKnownValue) {
+
+    mBuilder.setFramesPerCallback(192);
+    openAndCloseStream();
+    ASSERT_EQ(mStream->getFramesPerCallback(), 192);
+}
+
+TEST_F(StreamClosedReturnValues, GetFormatReturnsLastKnownValue) {
+
+    mBuilder.setFormat(AudioFormat::I16);
+    openAndCloseStream();
+    ASSERT_EQ(mStream->getFormat(), AudioFormat::I16);
+}
+
+TEST_F(StreamClosedReturnValues, GetBufferSizeInFramesReturnsLastKnownValue) {
+
+    openStream();
+    int32_t bufferSize = mStream->getBufferSizeInFrames();
+    closeStream();
+    ASSERT_EQ(mStream->getBufferSizeInFrames(), bufferSize);
+}
+
+TEST_F(StreamClosedReturnValues, GetBufferCapacityInFramesReturnsLastKnownValue) {
+
+    openStream();
+    int32_t bufferCapacity = mStream->getBufferCapacityInFrames();
+    closeStream();
+    ASSERT_EQ(mStream->getBufferCapacityInFrames(), bufferCapacity);
+}
+
+TEST_F(StreamClosedReturnValues, GetSharingModeReturnsLastKnownValue) {
+
+    openStream();
+    SharingMode s = mStream->getSharingMode();
+    closeStream();
+    ASSERT_EQ(mStream->getSharingMode(), s);
+}
+
+TEST_F(StreamClosedReturnValues, GetPerformanceModeReturnsLastKnownValue) {
+
+    openStream();
+    PerformanceMode p = mStream->getPerformanceMode();
+    closeStream();
+    ASSERT_EQ(mStream->getPerformanceMode(), p);
+}
+
+TEST_F(StreamClosedReturnValues, GetDeviceIdReturnsLastKnownValue) {
+
+    openStream();
+    int32_t d = mStream->getDeviceId();
+    closeStream();
+    ASSERT_EQ(mStream->getDeviceId(), d);
+}
+
+TEST_F(StreamClosedReturnValues, GetCallbackReturnsLastKnownValue) {
+
+    AudioStreamCallback *callback = new MyCallback();
+    mBuilder.setCallback(callback);
+    openAndCloseStream();
+
+    AudioStreamCallback *callback2 = mStream->getCallback();
+    ASSERT_EQ(callback, callback2);
+}
+
+TEST_F(StreamClosedReturnValues, GetUsageReturnsLastKnownValue){
+    openStream();
+    Usage u = mStream->getUsage();
+    closeStream();
+    ASSERT_EQ(mStream->getUsage(), u);
+}
+
+TEST_F(StreamClosedReturnValues, GetContentTypeReturnsLastKnownValue){
+    openStream();
+    ContentType c = mStream->getContentType();
+    closeStream();
+    ASSERT_EQ(mStream->getContentType(), c);
+}
+
+TEST_F(StreamClosedReturnValues, GetInputPresetReturnsLastKnownValue){
+    openStream();
+    auto i = mStream->getInputPreset();
+    closeStream();
+    ASSERT_EQ(mStream->getInputPreset(), i);
+}
+
+TEST_F(StreamClosedReturnValues, GetSessionIdReturnsLastKnownValue){
+    openStream();
+    auto s = mStream->getSessionId();
+    closeStream();
+    ASSERT_EQ(mStream->getSessionId(), s);
+}
+
+TEST_F(StreamClosedReturnValues, StreamStateIsClosed){
+    openAndCloseStream();
+    ASSERT_EQ(mStream->getState(), StreamState::Closed);
+}
+
+TEST_F(StreamClosedReturnValues, GetXRunCountReturnsLastKnownValue){
+
+    openStream();
+    if (mStream->isXRunCountSupported()){
+        auto i = mStream->getXRunCount();
+        ASSERT_EQ(mStream->getXRunCount(), i);
+    }
+    closeStream();
+}
+
+TEST_F(StreamClosedReturnValues, GetFramesPerBurstReturnsLastKnownValue){
+
+    openStream();
+    auto f = mStream->getFramesPerBurst();
+    closeStream();
+    ASSERT_EQ(mStream->getFramesPerBurst(), f);
+}
+
+TEST_F(StreamClosedReturnValues, IsPlayingReturnsFalse){
+
+    openAndCloseStream();
+    ASSERT_FALSE(mStream->isPlaying());
+}
+
+TEST_F(StreamClosedReturnValues, GetBytesPerFrameReturnsLastKnownValue){
+    openStream();
+    auto f = mStream->getBytesPerFrame();
+    closeStream();
+    ASSERT_EQ(mStream->getBytesPerFrame(), f);
+}
+
+TEST_F(StreamClosedReturnValues, GetBytesPerSampleReturnsLastKnownValue){
+    openStream();
+    auto f = mStream->getBytesPerSample();
+    closeStream();
+    ASSERT_EQ(mStream->getBytesPerSample(), f);
+}
+
+TEST_F(StreamClosedReturnValues, GetFramesWrittenReturnsLastKnownValue){
+    mBuilder.setFormat(AudioFormat::I16);
+    mBuilder.setChannelCount(1);
+    openStream();
+    mStream->start();
+
+    int16_t buffer[4] = { 1, 2, 3, 4 };
+    Result r = mStream->write(&buffer, 4, 0);
+    if (r != Result::OK){
+        FAIL() << "Could not write to audio stream";
+    }
+
+    auto f = mStream->getFramesWritten();
+    ASSERT_EQ(f, 4);
+
+    closeStream();
+    ASSERT_EQ(mStream->getFramesWritten(), f);
+}
+
+// TODO: Reading a positive value doesn't work on OpenSL ES in this test - why?
+TEST_F(StreamClosedReturnValues, GetFramesReadReturnsLastKnownValue) {
+
+    mBuilder.setDirection(Direction::Input);
+    mBuilder.setFormat(AudioFormat::I16);
+    mBuilder.setChannelCount(1);
+
+    if (openStream()){
+        mStream->start();
+
+/*
+        int16_t buffer[192];
+        auto r = mStream->read(&buffer, 192, 0);
+        ASSERT_EQ(r.value(), 192);
+*/
+
+        auto f = mStream->getFramesRead();
+//        ASSERT_EQ(f, 192);
+
+        closeStream();
+        ASSERT_EQ(mStream->getFramesRead(), f);
+    };
+}
+
+TEST_F(StreamClosedReturnValues, GetTimestampReturnsErrorClosedIfSupported){
+
+    openStream();
+
+    int64_t framePosition;
+    int64_t presentationTime;
+
+    auto r = mStream->getTimestamp(CLOCK_MONOTONIC, &framePosition, &presentationTime);
+    bool isTimestampSupported = (r == Result::OK);
+
+    closeStream();
+
+    if (isTimestampSupported){
+        ASSERT_EQ(mStream->getTimestamp(CLOCK_MONOTONIC, &framePosition, &presentationTime), Result::ErrorClosed);
+    }
+}
+
+TEST_F(StreamClosedReturnValues, GetAudioApiReturnsLastKnownValue){
+    openStream();
+    AudioApi a = mStream->getAudioApi();
+    closeStream();
+    ASSERT_EQ(mStream->getAudioApi(), a);
+}
+
+TEST_F(StreamClosedReturnValues, GetUsesAAudioReturnsLastKnownValue){
+    openStream();
+    bool a = mStream->usesAAudio();
+    closeStream();
+    ASSERT_EQ(mStream->usesAAudio(), a);
+}
+
+TEST_F(StreamClosedReturnValues, StreamStateControlsReturnClosed){
+
+    openAndCloseStream();
+    EXPECT_EQ(mStream->close(), Result::ErrorClosed);
+    EXPECT_EQ(mStream->start(), Result::ErrorClosed);
+    EXPECT_EQ(mStream->pause(), Result::ErrorClosed);
+    EXPECT_EQ(mStream->flush(), Result::ErrorClosed);
+    EXPECT_EQ(mStream->stop(), Result::ErrorClosed);
+    EXPECT_EQ(mStream->requestStart(), Result::ErrorClosed);
+    EXPECT_EQ(mStream->requestPause(), Result::ErrorClosed);
+    EXPECT_EQ(mStream->requestFlush(), Result::ErrorClosed);
+    EXPECT_EQ(mStream->requestStop(), Result::ErrorClosed);
+}
+
+TEST_F(StreamClosedReturnValues, WaitForStateChangeReturnsClosed){
+
+    openAndCloseStream();
+    StreamState next;
+    ASSERT_EQ(mStream->waitForStateChange(StreamState::Open, &next, 0), Result::ErrorClosed);
+}