mirror of
https://github.com/bolucat/Archive.git
synced 2025-11-03 02:53:53 +08:00
Update On Tue Sep 16 20:39:27 CEST 2025
This commit is contained in:
215
clash-meta/common/queue/queue_test.go
Normal file
215
clash-meta/common/queue/queue_test.go
Normal file
@@ -0,0 +1,215 @@
|
||||
package queue
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// TestQueuePut tests the Put method of Queue
|
||||
func TestQueuePut(t *testing.T) {
|
||||
// Initialize a new queue
|
||||
q := New[int](10)
|
||||
|
||||
// Test putting a single item
|
||||
q.Put(1)
|
||||
assert.Equal(t, int64(1), q.Len(), "Queue length should be 1 after putting one item")
|
||||
|
||||
// Test putting multiple items
|
||||
q.Put(2, 3, 4)
|
||||
assert.Equal(t, int64(4), q.Len(), "Queue length should be 4 after putting three more items")
|
||||
|
||||
// Test putting zero items (should not change queue)
|
||||
q.Put()
|
||||
assert.Equal(t, int64(4), q.Len(), "Queue length should remain unchanged when putting zero items")
|
||||
}
|
||||
|
||||
// TestQueuePop tests the Pop method of Queue
|
||||
func TestQueuePop(t *testing.T) {
|
||||
// Initialize a new queue with items
|
||||
q := New[int](10)
|
||||
q.Put(1, 2, 3)
|
||||
|
||||
// Test popping items in FIFO order
|
||||
item := q.Pop()
|
||||
assert.Equal(t, 1, item, "First item popped should be 1")
|
||||
assert.Equal(t, int64(2), q.Len(), "Queue length should be 2 after popping one item")
|
||||
|
||||
item = q.Pop()
|
||||
assert.Equal(t, 2, item, "Second item popped should be 2")
|
||||
assert.Equal(t, int64(1), q.Len(), "Queue length should be 1 after popping two items")
|
||||
|
||||
item = q.Pop()
|
||||
assert.Equal(t, 3, item, "Third item popped should be 3")
|
||||
assert.Equal(t, int64(0), q.Len(), "Queue length should be 0 after popping all items")
|
||||
}
|
||||
|
||||
// TestQueuePopEmpty tests the Pop method on an empty queue
|
||||
func TestQueuePopEmpty(t *testing.T) {
|
||||
// Initialize a new empty queue
|
||||
q := New[int](0)
|
||||
|
||||
// Test popping from an empty queue
|
||||
item := q.Pop()
|
||||
assert.Equal(t, 0, item, "Popping from an empty queue should return the zero value")
|
||||
assert.Equal(t, int64(0), q.Len(), "Queue length should remain 0 after popping from an empty queue")
|
||||
}
|
||||
|
||||
// TestQueueLast tests the Last method of Queue
|
||||
func TestQueueLast(t *testing.T) {
|
||||
// Initialize a new queue with items
|
||||
q := New[int](10)
|
||||
q.Put(1, 2, 3)
|
||||
|
||||
// Test getting the last item
|
||||
item := q.Last()
|
||||
assert.Equal(t, 3, item, "Last item should be 3")
|
||||
assert.Equal(t, int64(3), q.Len(), "Queue length should remain unchanged after calling Last")
|
||||
|
||||
// Test Last on an empty queue
|
||||
emptyQ := New[int](0)
|
||||
emptyItem := emptyQ.Last()
|
||||
assert.Equal(t, 0, emptyItem, "Last on an empty queue should return the zero value")
|
||||
}
|
||||
|
||||
// TestQueueCopy tests the Copy method of Queue
|
||||
func TestQueueCopy(t *testing.T) {
|
||||
// Initialize a new queue with items
|
||||
q := New[int](10)
|
||||
q.Put(1, 2, 3)
|
||||
|
||||
// Test copying the queue
|
||||
copy := q.Copy()
|
||||
assert.Equal(t, 3, len(copy), "Copy should have the same number of items as the original queue")
|
||||
assert.Equal(t, 1, copy[0], "First item in copy should be 1")
|
||||
assert.Equal(t, 2, copy[1], "Second item in copy should be 2")
|
||||
assert.Equal(t, 3, copy[2], "Third item in copy should be 3")
|
||||
|
||||
// Verify that modifying the copy doesn't affect the original queue
|
||||
copy[0] = 99
|
||||
assert.Equal(t, 1, q.Pop(), "Original queue should not be affected by modifying the copy")
|
||||
}
|
||||
|
||||
// TestQueueLen tests the Len method of Queue
|
||||
func TestQueueLen(t *testing.T) {
|
||||
// Initialize a new empty queue
|
||||
q := New[int](10)
|
||||
assert.Equal(t, int64(0), q.Len(), "New queue should have length 0")
|
||||
|
||||
// Add items and check length
|
||||
q.Put(1, 2)
|
||||
assert.Equal(t, int64(2), q.Len(), "Queue length should be 2 after putting two items")
|
||||
|
||||
// Remove an item and check length
|
||||
q.Pop()
|
||||
assert.Equal(t, int64(1), q.Len(), "Queue length should be 1 after popping one item")
|
||||
}
|
||||
|
||||
// TestQueueNew tests the New constructor
|
||||
func TestQueueNew(t *testing.T) {
|
||||
// Test creating a new queue with different hints
|
||||
q1 := New[int](0)
|
||||
assert.NotNil(t, q1, "New queue should not be nil")
|
||||
assert.Equal(t, int64(0), q1.Len(), "New queue should have length 0")
|
||||
|
||||
q2 := New[int](10)
|
||||
assert.NotNil(t, q2, "New queue should not be nil")
|
||||
assert.Equal(t, int64(0), q2.Len(), "New queue should have length 0")
|
||||
|
||||
// Test with a different type
|
||||
q3 := New[string](5)
|
||||
assert.NotNil(t, q3, "New queue should not be nil")
|
||||
assert.Equal(t, int64(0), q3.Len(), "New queue should have length 0")
|
||||
}
|
||||
|
||||
// TestQueueConcurrency tests the concurrency safety of Queue
|
||||
func TestQueueConcurrency(t *testing.T) {
|
||||
// Initialize a new queue
|
||||
q := New[int](100)
|
||||
|
||||
// Number of goroutines and operations
|
||||
goroutines := 10
|
||||
operations := 100
|
||||
|
||||
// Wait group to synchronize goroutines
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(goroutines * 2) // For both producers and consumers
|
||||
|
||||
// Start producer goroutines
|
||||
for i := 0; i < goroutines; i++ {
|
||||
go func(id int) {
|
||||
defer wg.Done()
|
||||
for j := 0; j < operations; j++ {
|
||||
q.Put(id*operations + j)
|
||||
// Small sleep to increase chance of race conditions
|
||||
time.Sleep(time.Microsecond)
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
// Start consumer goroutines
|
||||
consumed := make(chan int, goroutines*operations)
|
||||
for i := 0; i < goroutines; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := 0; j < operations; j++ {
|
||||
// Try to pop an item, but don't block if queue is empty
|
||||
// Use a mutex to avoid race condition between Len() check and Pop()
|
||||
q.lock.Lock()
|
||||
if len(q.items) > 0 {
|
||||
item := q.items[0]
|
||||
q.items = q.items[1:]
|
||||
q.lock.Unlock()
|
||||
consumed <- item
|
||||
} else {
|
||||
q.lock.Unlock()
|
||||
}
|
||||
// Small sleep to increase chance of race conditions
|
||||
time.Sleep(time.Microsecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait for all goroutines to finish
|
||||
wg.Wait()
|
||||
// Close the consumed channel
|
||||
close(consumed)
|
||||
|
||||
// Count the number of consumed items
|
||||
consumedCount := 0
|
||||
for range consumed {
|
||||
consumedCount++
|
||||
}
|
||||
|
||||
// Check that the queue is in a consistent state
|
||||
totalItems := goroutines * operations
|
||||
remaining := int(q.Len())
|
||||
assert.Equal(t, totalItems, consumedCount+remaining, "Total items should equal consumed items plus remaining items")
|
||||
}
|
||||
|
||||
// TestQueueWithDifferentTypes tests the Queue with different types
|
||||
func TestQueueWithDifferentTypes(t *testing.T) {
|
||||
// Test with string type
|
||||
qString := New[string](5)
|
||||
qString.Put("hello", "world")
|
||||
assert.Equal(t, int64(2), qString.Len(), "Queue length should be 2")
|
||||
assert.Equal(t, "hello", qString.Pop(), "First item should be 'hello'")
|
||||
assert.Equal(t, "world", qString.Pop(), "Second item should be 'world'")
|
||||
|
||||
// Test with struct type
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
qStruct := New[Person](5)
|
||||
qStruct.Put(Person{Name: "Alice", Age: 30}, Person{Name: "Bob", Age: 25})
|
||||
assert.Equal(t, int64(2), qStruct.Len(), "Queue length should be 2")
|
||||
|
||||
firstPerson := qStruct.Pop()
|
||||
assert.Equal(t, "Alice", firstPerson.Name, "First person's name should be 'Alice'")
|
||||
secondPerson := qStruct.Pop()
|
||||
assert.Equal(t, "Bob", secondPerson.Name, "Second person's name should be 'Bob'")
|
||||
}
|
||||
Reference in New Issue
Block a user