Skip to content

Commit 3056213

Browse files
author
fupeng1
committed
fix: testing error
1 parent 8eed43e commit 3056213

File tree

4 files changed

+90
-73
lines changed

4 files changed

+90
-73
lines changed

promise.go

Lines changed: 70 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func WithResolvers[T any]() (*Promise[T], func(T), func(error)) {
2020
func WithResolversWithMgr[T any](manager *PromiseMgr) (*Promise[T], func(T), func(error)) {
2121
p := &Promise[T]{
2222
manager: manager,
23+
done: make(chan struct{}),
2324
}
2425

2526
p.state.Store(Pending)
@@ -40,6 +41,7 @@ func WithResolversWithMgr[T any](manager *PromiseMgr) (*Promise[T], func(T), fun
4041
func NewWithMgr[T any](manager *PromiseMgr, executor func(resolve func(T), reject func(error))) *Promise[T] {
4142
p := &Promise[T]{
4243
manager: manager,
44+
done: make(chan struct{}),
4345
}
4446

4547
p.state.Store(Pending)
@@ -83,7 +85,6 @@ func NewWithMgr[T any](manager *PromiseMgr, executor func(resolve func(T), rejec
8385
return p
8486
}
8587

86-
// resolve fulfills the Promise
8788
func (p *Promise[T]) resolve(value T) {
8889
if !p.setState(Fulfilled) {
8990
return
@@ -92,9 +93,6 @@ func (p *Promise[T]) resolve(value T) {
9293
p.setValue(value)
9394

9495
p.mu.Lock()
95-
if p.done == nil {
96-
p.done = make(chan struct{})
97-
}
9896
select {
9997
case <-p.done:
10098
p.mu.Unlock()
@@ -120,7 +118,6 @@ func (p *Promise[T]) resolve(value T) {
120118
}
121119
}
122120

123-
// reject rejects the Promise
124121
func (p *Promise[T]) reject(err error) {
125122
if !p.setState(Rejected) {
126123
return
@@ -130,9 +127,6 @@ func (p *Promise[T]) reject(err error) {
130127
p.setError(finalErr)
131128

132129
p.mu.Lock()
133-
if p.done == nil {
134-
p.done = make(chan struct{})
135-
}
136130
select {
137131
case <-p.done:
138132
p.mu.Unlock()
@@ -167,7 +161,7 @@ func (p *Promise[T]) reject(err error) {
167161

168162
func (p *Promise[T]) Then(onFulfilled func(T) any, onRejected func(error) any) *Promise[any] {
169163
next := &Promise[any]{
170-
done: nil,
164+
done: make(chan struct{}),
171165
manager: p.manager,
172166
}
173167

@@ -225,7 +219,7 @@ func (p *Promise[T]) Catch(onRejected func(error) any) *Promise[any] {
225219

226220
func (p *Promise[T]) Finally(onFinally func()) *Promise[T] {
227221
next := &Promise[T]{
228-
done: nil,
222+
done: make(chan struct{}),
229223
manager: p.manager,
230224
}
231225

@@ -272,30 +266,62 @@ func (p *Promise[T]) Finally(onFinally func()) *Promise[T] {
272266
}
273267

274268
func (p *Promise[T]) Await() (T, error) {
275-
p.mu.Lock()
276-
if p.done == nil {
277-
p.done = make(chan struct{})
269+
state := p.getState()
270+
if state == Fulfilled {
271+
if value, ok := p.getValue(); ok {
272+
return value, nil
273+
}
278274
}
275+
if state == Rejected {
276+
if err, ok := p.getError(); ok {
277+
var zero T
278+
return zero, err
279+
}
280+
}
281+
282+
p.mu.Lock()
279283
done := p.done
280284
p.mu.Unlock()
281285

282286
<-done
283287

284-
if p.getState() == Fulfilled {
285-
value, _ := p.getValue()
286-
return value, nil
288+
state = p.getState()
289+
if state == Fulfilled {
290+
if value, ok := p.getValue(); ok {
291+
return value, nil
292+
}
293+
var zero T
294+
return zero, &PromiseError{
295+
Message: "Promise fulfilled but value not available",
296+
Type: RejectionError,
297+
}
287298
}
299+
288300
var zero T
289-
err, _ := p.getError()
290-
return zero, err
301+
if err, ok := p.getError(); ok {
302+
return zero, err
303+
}
304+
return zero, &PromiseError{
305+
Message: "Promise rejected but error not available",
306+
Type: RejectionError,
307+
}
291308
}
292309

293-
// AwaitWithContext waits for Promise completion with context
294310
func (p *Promise[T]) AwaitWithContext(ctx context.Context) (T, error) {
295-
p.mu.Lock()
296-
if p.done == nil {
297-
p.done = make(chan struct{})
311+
state := p.getState()
312+
if state == Fulfilled {
313+
if value, ok := p.getValue(); ok {
314+
return value, nil
315+
}
298316
}
317+
if state == Rejected {
318+
if err, ok := p.getError(); ok {
319+
var zero T
320+
return zero, err
321+
}
322+
}
323+
324+
p.mu.Lock()
299325
done := p.done
300326
p.mu.Unlock()
301327

@@ -306,36 +332,44 @@ func (p *Promise[T]) AwaitWithContext(ctx context.Context) (T, error) {
306332
case <-done:
307333
}
308334

309-
if p.getState() == Fulfilled {
310-
value, _ := p.getValue()
311-
return value, nil
335+
state = p.getState()
336+
if state == Fulfilled {
337+
if value, ok := p.getValue(); ok {
338+
return value, nil
339+
}
340+
var zero T
341+
return zero, &PromiseError{
342+
Message: "Promise fulfilled but value not available",
343+
Type: RejectionError,
344+
}
312345
}
346+
313347
var zero T
314-
err, _ := p.getError()
315-
return zero, err
348+
if err, ok := p.getError(); ok {
349+
return zero, err
350+
}
351+
return zero, &PromiseError{
352+
Message: "Promise rejected but error not available",
353+
Type: RejectionError,
354+
}
316355
}
317356

318-
// State gets the Promise state
319357
func (p *Promise[T]) State() State {
320358
return p.getState()
321359
}
322360

323-
// IsPending checks if Promise is pending
324361
func (p *Promise[T]) IsPending() bool {
325362
return p.State() == Pending
326363
}
327364

328-
// IsFulfilled checks if Promise is fulfilled
329365
func (p *Promise[T]) IsFulfilled() bool {
330366
return p.State() == Fulfilled
331367
}
332368

333-
// IsRejected checks if Promise is rejected
334369
func (p *Promise[T]) IsRejected() bool {
335370
return p.State() == Rejected
336371
}
337372

338-
// safeCallback wraps callback with panic recovery
339373
func safeCallback[T any](callback func(T) any, value T, next *Promise[any]) {
340374
if next == nil {
341375
callback(value)
@@ -367,7 +401,6 @@ func safeCallback[T any](callback func(T) any, value T, next *Promise[any]) {
367401
next.resolve(result)
368402
}
369403

370-
// safeErrorCallback wraps error callback with panic recovery
371404
func safeErrorCallback(callback func(error) any, err error, next *Promise[any]) {
372405
if next == nil {
373406
callback(err)
@@ -378,21 +411,19 @@ func safeErrorCallback(callback func(error) any, err error, next *Promise[any])
378411
if r := recover(); r != nil {
379412
var panicErr error
380413
if e, ok := r.(error); ok {
381-
// Wrap original error, preserve context
382414
panicErr = &PromiseError{
383415
Message: "panic in error callback",
384416
Cause: e,
385417
Type: PanicError,
386-
OriginalError: err, // Preserve original error being processed
418+
OriginalError: err,
387419
}
388420
} else {
389-
// Non-error panic, wrap as error but preserve original value
390421
panicErr = &PromiseError{
391422
Message: fmt.Sprintf("panic in error callback: %v", r),
392423
Cause: nil,
393424
Type: PanicError,
394425
Value: r,
395-
OriginalError: err, // Preserve original error being processed
426+
OriginalError: err,
396427
}
397428
}
398429
next.reject(panicErr)
@@ -403,7 +434,6 @@ func safeErrorCallback(callback func(error) any, err error, next *Promise[any])
403434
next.resolve(result)
404435
}
405436

406-
// safeFinallyCallback wraps finally callback with panic recovery
407437
func safeFinallyCallback[T any](callback func(), next *Promise[T], value T, err error) {
408438
if next == nil {
409439
callback()
@@ -414,28 +444,25 @@ func safeFinallyCallback[T any](callback func(), next *Promise[T], value T, err
414444
if r := recover(); r != nil {
415445
var panicErr error
416446
if e, ok := r.(error); ok {
417-
// Wrap original error, preserve context
418447
panicErr = &PromiseError{
419448
Message: "panic in finally callback",
420449
Cause: e,
421450
Type: PanicError,
422-
OriginalError: err, // Preserve original error (if any)
451+
OriginalError: err,
423452
}
424453
} else {
425-
// Non-error panic, wrap as error but preserve original value
426454
panicErr = &PromiseError{
427455
Message: fmt.Sprintf("panic in finally callback: %v", r),
428456
Cause: nil,
429457
Type: PanicError,
430458
Value: r,
431-
OriginalError: err, // Preserve original error (if any)
459+
OriginalError: err,
432460
}
433461
}
434462
next.reject(panicErr)
435463
return
436464
}
437465

438-
// Finally callback completed successfully, resolve with original value
439466
if err == nil {
440467
next.resolve(value)
441468
} else {

promise_test.go

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ import (
1212

1313
// TestMain provides setup and teardown for the entire test suite
1414
func TestMain(m *testing.M) {
15-
mgr := GetDefaultMgr()
16-
1715
// Run tests
1816
code := m.Run()
1917

20-
mgr.Close()
18+
// Cleanup: close the current default manager and wait for shutdown
19+
currentMgr := GetDefaultMgr()
20+
currentMgr.Close()
21+
currentMgr.WaitForShutdown()
2122

2223
if code != 0 {
2324
panic(fmt.Sprintf("Tests failed with code %d", code))
@@ -1086,15 +1087,11 @@ func TestWithResolvers(t *testing.T) {
10861087
t.Run("Multiple resolves should only take first", func(t *testing.T) {
10871088
promise, resolve, _ := WithResolvers[string]()
10881089

1089-
// Multiple resolves
1090-
go func() {
1091-
time.Sleep(5 * time.Millisecond)
1092-
resolve("first")
1093-
}()
1094-
go func() {
1095-
time.Sleep(10 * time.Millisecond)
1096-
resolve("second")
1097-
}()
1090+
// First resolve should succeed
1091+
resolve("first")
1092+
1093+
// Second resolve should be ignored (no effect)
1094+
resolve("second")
10981095

10991096
result, err := promise.Await()
11001097
if err != nil {
@@ -1108,19 +1105,16 @@ func TestWithResolvers(t *testing.T) {
11081105
t.Run("Multiple rejects should only take first", func(t *testing.T) {
11091106
promise, _, reject := WithResolvers[string]()
11101107

1111-
// Multiple rejects
1112-
go func() {
1113-
time.Sleep(5 * time.Millisecond)
1114-
reject(errors.New("first reject"))
1115-
}()
1116-
go func() {
1117-
time.Sleep(10 * time.Millisecond)
1118-
reject(errors.New("second reject"))
1119-
}()
1108+
// First reject should succeed
1109+
reject(errors.New("first reject"))
1110+
1111+
// Second reject should be ignored (no effect)
1112+
reject(errors.New("second reject"))
11201113

11211114
_, err := promise.Await()
11221115
if err == nil {
11231116
t.Error("Expected error, but got none")
1117+
return
11241118
}
11251119
if !strings.Contains(err.Error(), "first reject") {
11261120
t.Errorf("Expected error to contain 'first reject', but got: %v", err)

types.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,7 @@ func (p *Promise[T]) setState(state State) bool {
118118
}
119119

120120
// Now try to transition from Pending to target state
121-
if p.state.CompareAndSwap(Pending, state) {
122-
return true
123-
}
124-
125-
// If transition failed, check current state
126-
currentState := p.state.Load().(State)
127-
return currentState == state // Return true if already in target state
121+
return p.state.CompareAndSwap(Pending, state)
128122
}
129123

130124
// Helper function: safely get value

utils.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import (
77

88
func Resolve[T any](value T) *Promise[T] {
99
p := &Promise[T]{
10-
done: make(chan struct{}),
10+
done: make(chan struct{}),
11+
manager: GetDefaultMgr(),
1112
}
1213

1314
// Use helper functions to set state and value atomically
@@ -19,7 +20,8 @@ func Resolve[T any](value T) *Promise[T] {
1920

2021
func Reject[T any](err error) *Promise[T] {
2122
p := &Promise[T]{
22-
done: make(chan struct{}),
23+
done: make(chan struct{}),
24+
manager: GetDefaultMgr(),
2325
}
2426

2527
// Use helper functions to set state and error atomically

0 commit comments

Comments
 (0)