import heapq

# === heappush and heappop ===
h = []
heapq.heappush(h, 3)
heapq.heappush(h, 1)
heapq.heappush(h, 4)
heapq.heappush(h, 1)
heapq.heappush(h, 5)
assert h[0] == 1, 'heap min is 1'
assert heapq.heappop(h) == 1, 'heappop returns 1'
assert heapq.heappop(h) == 1, 'heappop returns 1 again'
assert heapq.heappop(h) == 3, 'heappop returns 3'

# === heapify ===
data = [5, 3, 8, 1, 2]
heapq.heapify(data)
assert data[0] == 1, 'heapify min element'
# verify heap property: parent <= children
for i in range(len(data)):
    left = 2 * i + 1
    right = 2 * i + 2
    if left < len(data):
        assert data[i] <= data[left], 'heap property left child'
    if right < len(data):
        assert data[i] <= data[right], 'heap property right child'

# === pop all in order ===
data2 = [5, 3, 8, 1, 2, 7, 4]
heapq.heapify(data2)
result = []
while len(data2) > 0:
    result.append(heapq.heappop(data2))
assert result == [1, 2, 3, 4, 5, 7, 8], 'sorted via heappop'

# === nlargest ===
nums = [1, 8, 2, 7, 3, 6, 4, 5]
assert heapq.nlargest(3, nums) == [8, 7, 6], 'nlargest 3'
assert heapq.nlargest(1, nums) == [8], 'nlargest 1'

# === nsmallest ===
assert heapq.nsmallest(3, nums) == [1, 2, 3], 'nsmallest 3'
assert heapq.nsmallest(1, nums) == [1], 'nsmallest 1'

# === edge cases ===
assert heapq.nlargest(0, nums) == [], 'nlargest 0'
assert heapq.nsmallest(0, nums) == [], 'nsmallest 0'

# === heappushpop ===
h2 = [1, 3, 5]
heapq.heapify(h2)
# Push 0 (smaller than min) — should get 0 back immediately
assert heapq.heappushpop(h2, 0) == 0, 'heappushpop smaller item'
assert h2[0] == 1, 'heappushpop did not modify heap'

# Push 2 (between 1 and 3) — should get 1 back
assert heapq.heappushpop(h2, 2) == 1, 'heappushpop returns old min'
assert h2[0] == 2, 'heappushpop new min is 2'

# Push 10 (larger than all) — should get current min back
h3 = [1, 3, 5]
heapq.heapify(h3)
assert heapq.heappushpop(h3, 10) == 1, 'heappushpop larger item returns old min'

# Empty heap
h_empty = []
assert heapq.heappushpop(h_empty, 42) == 42, 'heappushpop empty returns item'
assert len(h_empty) == 0, 'heappushpop empty keeps heap empty'

# === heapreplace ===
h4 = [1, 3, 5]
heapq.heapify(h4)
assert heapq.heapreplace(h4, 2) == 1, 'heapreplace returns old min'
assert h4[0] == 2, 'heapreplace new min is 2'
assert len(h4) == 3, 'heapreplace keeps same length'

h5 = [1, 3, 5]
heapq.heapify(h5)
assert heapq.heapreplace(h5, 0) == 1, 'heapreplace with smaller item returns old min'
assert h5[0] == 0, 'heapreplace new min is 0'

# === from import ===
from heapq import heappop, heappush

h6 = []
heappush(h6, 10)
heappush(h6, 5)
assert heappop(h6) == 5, 'from import heappop'
