using Invercargill; using Invercargill.DataStructures; void fifo_tests() { Test.add_func("/invercargill/fifo/basic_push_pop", () => { var fifo = new Fifo(); // Push items fifo.push("first"); fifo.push("second"); fifo.push("third"); // Pop in insertion order (FIFO) var first = fifo.pop(); var second = fifo.pop(); var third = fifo.pop(); assert_cmpstr("first", CompareOperator.EQ, first); assert_cmpstr("second", CompareOperator.EQ, second); assert_cmpstr("third", CompareOperator.EQ, third); }); Test.add_func("/invercargill/fifo/peek functionality", () => { var fifo = new Fifo(); fifo.push(1); fifo.push(2); fifo.push(3); // Peek should return front item without removing var front = fifo.peek(); assert_cmpint(1, CompareOperator.EQ, front); // Pop should still return 1 var popped = fifo.pop(); assert_cmpint(1, CompareOperator.EQ, popped); // Peek now should return 2 var new_front = fifo.peek(); assert_cmpint(2, CompareOperator.EQ, new_front); }); Test.add_func("/invercargill/fifo/empty_fifo_behavior", () => { // Test peek on empty fifo var fifo1 = new Fifo(); try { fifo1.peek(); assert_not_reached(); } catch (SequenceError e) { assert_cmpstr("No elements in queue", CompareOperator.EQ, e.message); } // Test pop on empty fifo - need to unblock first var fifo2 = new Fifo(); fifo2.unblock(); try { fifo2.pop(); assert_not_reached(); } catch (SequenceError e) { assert_cmpstr("No elements in unblocked queue to pop", CompareOperator.EQ, e.message); } }); Test.add_func("/invercargill/fifo/push_all", () => { var fifo = new Fifo(); var items = new Series(); items.add(1); items.add(2); items.add(3); // Push all items fifo.push_all(items); // Should pop in insertion order assert_cmpint(1, CompareOperator.EQ, fifo.pop()); assert_cmpint(2, CompareOperator.EQ, fifo.pop()); assert_cmpint(3, CompareOperator.EQ, fifo.pop()); }); Test.add_func("/invercargill/fifo/enumerable_behavior", () => { var fifo = new Fifo(); fifo.push("first"); fifo.push("second"); fifo.push("third"); fifo.unblock(); // Iteration should return items in FIFO order var tracker = fifo.get_tracker(); var items = new string[3]; var index = 0; while (tracker.has_next()) { items[index++] = tracker.get_next(); } assert_cmpstr("first", CompareOperator.EQ, items[0]); assert_cmpstr("second", CompareOperator.EQ, items[1]); assert_cmpstr("third", CompareOperator.EQ, items[2]); }); Test.add_func("/invercargill/fifo/blocking_behavior", () => { var fifo = new Fifo(); bool thread_started = false; bool thread_finished = false; // Start a thread that will wait for an item Thread thread = new Thread("test-thread", () => { thread_started = true; var item = fifo.pop(); assert_cmpstr("test_item", CompareOperator.EQ, item); thread_finished = true; return null; }); // Wait for thread to start and block while (!thread_started) { Thread.usleep(1000); // 1ms } // Give additional time for thread to block on pop() Thread.usleep(50000); // 50ms // Push an item to unblock the thread fifo.push("test_item"); // Wait for thread to finish thread.join(); assert_true(thread_finished); }); Test.add_func("/invercargill/fifo/unblock_behavior", () => { var fifo = new Fifo(); bool thread_started = false; bool exception_thrown = false; // Start a thread that will wait for an item Thread thread = new Thread("test-thread", () => { thread_started = true; try { var item = fifo.pop(); // This should throw after unblock assert_not_reached(); } catch (SequenceError e) { assert_cmpstr("No elements in unblocked queue to pop", CompareOperator.EQ, e.message); exception_thrown = true; } return null; }); // Wait for thread to start and block while (!thread_started) { Thread.usleep(1000); // 1ms } // Give additional time for thread to block on pop() Thread.usleep(50000); // 50ms // Unblock the fifo fifo.unblock(); // Wait for thread to finish thread.join(); assert_true(exception_thrown); }); Test.add_func("/invercargill/fifo/try_peek_and_try_pop", () => { var fifo = new Fifo(); // Try operations on empty fifo string item; assert_false(fifo.try_peek(out item)); assert_null(item); string popped; fifo.unblock(); assert_false(fifo.try_pop(out popped)); assert_null(popped); // Add an item fifo.push("test"); // Try operations should now succeed assert_true(fifo.try_peek(out item)); assert_cmpstr("test", CompareOperator.EQ, item); assert_true(fifo.try_pop(out popped)); assert_cmpstr("test", CompareOperator.EQ, popped); // Should be empty again assert_false(fifo.try_pop(out popped)); assert_null(popped); }); Test.add_func("/invercargill/fifo/push_start", () => { var fifo = new Fifo(); // Add items normally fifo.push("first"); fifo.push("second"); // Add item to start fifo.push_start("zero"); // Should pop: zero, first, second assert_cmpstr("zero", CompareOperator.EQ, fifo.pop()); assert_cmpstr("first", CompareOperator.EQ, fifo.pop()); assert_cmpstr("second", CompareOperator.EQ, fifo.pop()); }); }