import { assert, describe, it } from "@effect/vitest" import { Effect, Fiber, Option, Order, TxPriorityQueue } from "effect" describe("TxPriorityQueue", () => { describe("constructors", () => { it.effect("empty creates an empty queue", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.empty(Order.Number) const s = yield* TxPriorityQueue.size(pq) assert.strictEqual(s, 0) assert.isTrue(yield* TxPriorityQueue.isEmpty(pq)) }))) it.effect("fromIterable creates a sorted queue", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [3, 1, 2]) const all = yield* TxPriorityQueue.toArray(pq) assert.deepStrictEqual(all, [1, 2, 3]) }))) it.effect("make creates from variadic args", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.make(Order.Number)(5, 3, 1, 4, 2) const all = yield* TxPriorityQueue.toArray(pq) assert.deepStrictEqual(all, [1, 2, 3, 4, 5]) }))) }) describe("getters", () => { it.effect("size returns number of elements", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [1, 2, 3]) assert.strictEqual(yield* TxPriorityQueue.size(pq), 3) }))) it.effect("isEmpty/isNonEmpty", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.empty(Order.Number) assert.isTrue(yield* TxPriorityQueue.isEmpty(pq)) assert.isFalse(yield* TxPriorityQueue.isNonEmpty(pq)) yield* TxPriorityQueue.offer(pq, 1) assert.isFalse(yield* TxPriorityQueue.isEmpty(pq)) assert.isTrue(yield* TxPriorityQueue.isNonEmpty(pq)) }))) it.effect("peek returns smallest without removing", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [3, 1, 2]) const top = yield* TxPriorityQueue.peek(pq) assert.strictEqual(top, 1) assert.strictEqual(yield* TxPriorityQueue.size(pq), 3) }))) it.effect("peekOption returns None when empty", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.empty(Order.Number) const result = yield* TxPriorityQueue.peekOption(pq) assert.isTrue(Option.isNone(result)) }))) it.effect("peekOption returns Some when non-empty", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [3, 1]) const result = yield* TxPriorityQueue.peekOption(pq) assert.isTrue(Option.isSome(result)) if (Option.isSome(result)) { assert.strictEqual(result.value, 1) } }))) }) describe("mutations", () => { it.effect("offer + take returns elements in priority order", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.empty(Order.Number) yield* TxPriorityQueue.offer(pq, 3) yield* TxPriorityQueue.offer(pq, 1) yield* TxPriorityQueue.offer(pq, 2) assert.strictEqual(yield* TxPriorityQueue.take(pq), 1) assert.strictEqual(yield* TxPriorityQueue.take(pq), 2) assert.strictEqual(yield* TxPriorityQueue.take(pq), 3) }))) it.effect("duplicate priorities are all returned", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [2, 1, 2, 1, 3]) const all = yield* TxPriorityQueue.takeAll(pq) assert.deepStrictEqual(all, [1, 1, 2, 2, 3]) }))) it.effect("take on empty retries until offer", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.empty(Order.Number) const fiber = yield* Effect.forkChild(TxPriorityQueue.take(pq)) yield* TxPriorityQueue.offer(pq, 42) const value = yield* Fiber.join(fiber) assert.strictEqual(value, 42) }))) it.effect("takeOption returns None when empty", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.empty(Order.Number) const result = yield* TxPriorityQueue.takeOption(pq) assert.isTrue(Option.isNone(result)) }))) it.effect("takeUpTo returns min(n, size) elements in order", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [5, 3, 1, 4, 2]) const top3 = yield* TxPriorityQueue.takeUpTo(pq, 3) assert.deepStrictEqual(top3, [1, 2, 3]) assert.strictEqual(yield* TxPriorityQueue.size(pq), 2) }))) it.effect("takeUpTo with n > size returns all", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [2, 1]) const all = yield* TxPriorityQueue.takeUpTo(pq, 10) assert.deepStrictEqual(all, [1, 2]) assert.strictEqual(yield* TxPriorityQueue.size(pq), 0) }))) it.effect("offerAll inserts multiple elements", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.empty(Order.Number) yield* TxPriorityQueue.offerAll(pq, [3, 1, 2]) const all = yield* TxPriorityQueue.toArray(pq) assert.deepStrictEqual(all, [1, 2, 3]) }))) }) describe("filtering", () => { it.effect("removeIf removes matching elements", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [1, 2, 3, 4, 5]) yield* TxPriorityQueue.removeIf(pq, (n) => n % 2 === 0) const all = yield* TxPriorityQueue.takeAll(pq) assert.deepStrictEqual(all, [1, 3, 5]) }))) it.effect("retainIf keeps only matching elements", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [1, 2, 3, 4, 5]) yield* TxPriorityQueue.retainIf(pq, (n) => n % 2 === 0) const all = yield* TxPriorityQueue.takeAll(pq) assert.deepStrictEqual(all, [2, 4]) }))) }) describe("guards", () => { it.effect("isTxPriorityQueue", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.empty(Order.Number) assert.isTrue(TxPriorityQueue.isTxPriorityQueue(pq)) assert.isFalse(TxPriorityQueue.isTxPriorityQueue(null)) assert.isFalse(TxPriorityQueue.isTxPriorityQueue({ some: "object" })) assert.isFalse(TxPriorityQueue.isTxPriorityQueue([1, 2, 3])) }))) }) describe("concurrency", () => { it.effect("concurrent offer and take", () => Effect.tx(Effect.gen(function*() { const pq = yield* TxPriorityQueue.empty(Order.Number) const fiber = yield* Effect.forkChild( Effect.all([ TxPriorityQueue.take(pq), TxPriorityQueue.take(pq), TxPriorityQueue.take(pq) ]) ) yield* TxPriorityQueue.offerAll(pq, [3, 1, 2]) const results = yield* Fiber.join(fiber) assert.deepStrictEqual(results, [1, 2, 3]) }))) }) describe("custom ordering", () => { it.effect("reverse order (max-first)", () => Effect.tx(Effect.gen(function*() { const reverseNumber: Order.Order = (a, b) => (a < b ? 1 : a > b ? -1 : 0) const pq = yield* TxPriorityQueue.fromIterable(reverseNumber, [1, 3, 2]) const first = yield* TxPriorityQueue.take(pq) assert.strictEqual(first, 3) }))) }) })