// Path: src/main/java/io/playpen/core/utils/process/ProcessBuffer.java
// public abstract class ProcessBuffer {
//     private final StringBuilder rumpBuffer = new StringBuilder(128);
//     private volatile boolean rumpBufferHasContents = false;
//     private final Lock lock = new ReentrantLock();
// 
//     public void append(CharBuffer buffer) {
//         // Okay, I'll admit it: this thing is literally a Rube Goldberg machine. But it works well enough!
//         StringBuilder found = new StringBuilder();
// 
//         if (rumpBufferHasContents) {
//             lock.lock();
//             try {
//                 found.append(rumpBuffer);
//                 rumpBuffer.delete(0, rumpBuffer.length());
//                 rumpBufferHasContents = false;
//             } finally {
//                 lock.unlock();
//             }
//         }
// 
//         for (int i = 0; i < buffer.remaining(); i++) {
//             char c = buffer.get(i);
//             if (c == '\r') {
//                 // When it looks like a hammer, there must be a sickle too.
//                 continue;
//             }
//             if (c == '\n') {
//                 if (found.length() == 0)
//                     continue;
//                 onOutput(found.toString());
//                 found.delete(0, found.length());
//             } else {
//                 found.append(c);
//             }
//         }
// 
//         // Consume the buffer.
//         buffer.position(buffer.remaining());
// 
//         if (found.length() != 0) {
//             lock.lock();
//             try {
//                 this.rumpBuffer.append(found);
//                 rumpBufferHasContents = true;
//             } finally {
//                 lock.unlock();
//             }
//         }
//     }
// 
//     protected abstract void onOutput(String output);
// }
// 
// Path: src/main/java/io/playpen/core/utils/process/ProcessBuffer.java
// public abstract class ProcessBuffer {
//     private final StringBuilder rumpBuffer = new StringBuilder(128);
//     private volatile boolean rumpBufferHasContents = false;
//     private final Lock lock = new ReentrantLock();
// 
//     public void append(CharBuffer buffer) {
//         // Okay, I'll admit it: this thing is literally a Rube Goldberg machine. But it works well enough!
//         StringBuilder found = new StringBuilder();
// 
//         if (rumpBufferHasContents) {
//             lock.lock();
//             try {
//                 found.append(rumpBuffer);
//                 rumpBuffer.delete(0, rumpBuffer.length());
//                 rumpBufferHasContents = false;
//             } finally {
//                 lock.unlock();
//             }
//         }
// 
//         for (int i = 0; i < buffer.remaining(); i++) {
//             char c = buffer.get(i);
//             if (c == '\r') {
//                 // When it looks like a hammer, there must be a sickle too.
//                 continue;
//             }
//             if (c == '\n') {
//                 if (found.length() == 0)
//                     continue;
//                 onOutput(found.toString());
//                 found.delete(0, found.length());
//             } else {
//                 found.append(c);
//             }
//         }
// 
//         // Consume the buffer.
//         buffer.position(buffer.remaining());
// 
//         if (found.length() != 0) {
//             lock.lock();
//             try {
//                 this.rumpBuffer.append(found);
//                 rumpBufferHasContents = true;
//             } finally {
//                 lock.unlock();
//             }
//         }
//     }
// 
//     protected abstract void onOutput(String output);
// }


import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import io.playpen.core.utils.process.ProcessBuffer;
import io.playpen.core.utils.process.ProcessBuffer;
import org.junit.Assert;
import org.junit.Test;
import java.nio.CharBuffer;
import java.util.List;
        buffer.append(CharBuffer.wrap(fullBuffer(strings)));

        sanityCheck(buffer);
    }

    @Test
    public void verifyIncompleteLine() {
        List<String> strings = Lists.newArrayList("Test", "Testing2");
        TestBuffer buffer = new TestBuffer(strings);
        buffer.append(CharBuffer.wrap(fullBuffer(strings) + "Potato"));

        sanityCheck(buffer);
    }

    @Test
    public void verifyLaterCompletedLine() {
        List<String> strings = Lists.newArrayList("Test", "Testing2", "Potato");
        TestBuffer buffer = new TestBuffer(strings);
        buffer.append(CharBuffer.wrap(String.join(LINE_SEPERATOR, strings)));
        buffer.append(CharBuffer.wrap(LINE_SEPERATOR));
        sanityCheck(buffer);
    }

    private static void sanityCheck(TestBuffer buffer) {
        if (!buffer.expected.isEmpty()) {
            int hasRead = buffer.origSize - buffer.expected.size();
            Assert.fail("Didn't read enough data (read " + hasRead + " lines, wanted " + buffer.origSize + " lines)");
        }
    }

// Path: src/main/java/io/playpen/core/utils/process/ProcessBuffer.java
// public abstract class ProcessBuffer {
//     private final StringBuilder rumpBuffer = new StringBuilder(128);
//     private volatile boolean rumpBufferHasContents = false;
//     private final Lock lock = new ReentrantLock();
// 
//     public void append(CharBuffer buffer) {
//         // Okay, I'll admit it: this thing is literally a Rube Goldberg machine. But it works well enough!
//         StringBuilder found = new StringBuilder();
// 
//         if (rumpBufferHasContents) {
//             lock.lock();
//             try {
//                 found.append(rumpBuffer);
//                 rumpBuffer.delete(0, rumpBuffer.length());
//                 rumpBufferHasContents = false;
//             } finally {
//                 lock.unlock();
//             }
//         }
// 
//         for (int i = 0; i < buffer.remaining(); i++) {
//             char c = buffer.get(i);
//             if (c == '\r') {
//                 // When it looks like a hammer, there must be a sickle too.
//                 continue;
//             }
//             if (c == '\n') {
//                 if (found.length() == 0)
//                     continue;
//                 onOutput(found.toString());
//                 found.delete(0, found.length());
//             } else {
//                 found.append(c);
//             }
//         }
// 
//         // Consume the buffer.
//         buffer.position(buffer.remaining());
// 
//         if (found.length() != 0) {
//             lock.lock();
//             try {
//                 this.rumpBuffer.append(found);
//                 rumpBufferHasContents = true;
//             } finally {
//                 lock.unlock();
//             }
//         }
//     }
// 
//     protected abstract void onOutput(String output);
// }
// 
// Path: src/main/java/io/playpen/core/utils/process/ProcessBuffer.java
// public abstract class ProcessBuffer {
//     private final StringBuilder rumpBuffer = new StringBuilder(128);
//     private volatile boolean rumpBufferHasContents = false;
//     private final Lock lock = new ReentrantLock();
// 
//     public void append(CharBuffer buffer) {
//         // Okay, I'll admit it: this thing is literally a Rube Goldberg machine. But it works well enough!
//         StringBuilder found = new StringBuilder();
// 
//         if (rumpBufferHasContents) {
//             lock.lock();
//             try {
//                 found.append(rumpBuffer);
//                 rumpBuffer.delete(0, rumpBuffer.length());
//                 rumpBufferHasContents = false;
//             } finally {
//                 lock.unlock();
//             }
//         }
// 
//         for (int i = 0; i < buffer.remaining(); i++) {
//             char c = buffer.get(i);
//             if (c == '\r') {
//                 // When it looks like a hammer, there must be a sickle too.
//                 continue;
//             }
//             if (c == '\n') {
//                 if (found.length() == 0)
//                     continue;
//                 onOutput(found.toString());
//                 found.delete(0, found.length());
//             } else {
//                 found.append(c);
//             }
//         }
// 
//         // Consume the buffer.
//         buffer.position(buffer.remaining());
// 
//         if (found.length() != 0) {
//             lock.lock();
//             try {
//                 this.rumpBuffer.append(found);
//                 rumpBufferHasContents = true;
//             } finally {
//                 lock.unlock();
//             }
//         }
//     }
// 
//     protected abstract void onOutput(String output);
// }


// Path: src/test/java/io/playpen/core/ProcessBufferTest.java
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import io.playpen.core.utils.process.ProcessBuffer;
import io.playpen.core.utils.process.ProcessBuffer;
import org.junit.Assert;
import org.junit.Test;
import java.nio.CharBuffer;
import java.util.List;

        buffer.append(CharBuffer.wrap(fullBuffer(strings)));

        sanityCheck(buffer);
    }

    @Test
    public void verifyIncompleteLine() {
        List<String> strings = Lists.newArrayList("Test", "Testing2");
        TestBuffer buffer = new TestBuffer(strings);
        buffer.append(CharBuffer.wrap(fullBuffer(strings) + "Potato"));

        sanityCheck(buffer);
    }

    @Test
    public void verifyLaterCompletedLine() {
        List<String> strings = Lists.newArrayList("Test", "Testing2", "Potato");
        TestBuffer buffer = new TestBuffer(strings);
        buffer.append(CharBuffer.wrap(String.join(LINE_SEPERATOR, strings)));
        buffer.append(CharBuffer.wrap(LINE_SEPERATOR));
        sanityCheck(buffer);
    }

    private static void sanityCheck(TestBuffer buffer) {
        if (!buffer.expected.isEmpty()) {
            int hasRead = buffer.origSize - buffer.expected.size();
            Assert.fail("Didn't read enough data (read " + hasRead + " lines, wanted " + buffer.origSize + " lines)");
        }
    }

    private class TestBuffer extends ProcessBuffer {