Socket Reader I
You are given a connected TCP socket. socket.recv(k) returns at most k bytes — possibly fewer, possibly just one — and returns an empty result once the peer has closed the connection (EOF). A line can arrive split across many recv calls, and one recv can contain several lines.
Build LineReader(socket) on top of it, keeping an internal buffer between calls. readLine() returns the next line as text, decoded as UTF-8, without its \n. Empty lines are preserved, a \r before the newline is kept as data, a final line with no trailing newline is still returned, and after that every call returns null.
stream: "a\nbb\n\nccc" readLine() -> "a", "bb", "", "ccc", null
The harness feeds your reader from a fake socket that fragments the stream at chosen offsets — sometimes in the middle of a multi-byte character — calls readLine a fixed number of times, and records each result. Results longer than 32 characters are shown as len:N:head:tail.
Hints
Hint 1
Loop: search the buffer for a newline; if there is none, call recv and append; when recv returns nothing, return whatever is left as the final line, then null forever.
Hint 2
Keep it linear: remember how far you already searched, so a long line arriving in small pieces is scanned once. Decode only once a full line is in hand, so a character split across two reads is never decoded in halves.