// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build goexperiment.synctest

package synctest_test

import (
	"context"
	"fmt"
	"testing/synctest"
	"time"
)

// This example demonstrates testing the context.AfterFunc function.
//
// AfterFunc registers a function to execute in a new goroutine
// after a context is canceled.
//
// The test verifies that the function is not run before the context is canceled,
// and is run after the context is canceled.
func Example_contextAfterFunc() {
	synctest.Run(func() {
		// Create a context.Context which can be canceled.
		ctx, cancel := context.WithCancel(context.Background())

		// context.AfterFunc registers a function to be called
		// when a context is canceled.
		afterFuncCalled := false
		context.AfterFunc(ctx, func() {
			afterFuncCalled = true
		})

		// The context has not been canceled, so the AfterFunc is not called.
		synctest.Wait()
		fmt.Printf("before context is canceled: afterFuncCalled=%v\n", afterFuncCalled)

		// Cancel the context and wait for the AfterFunc to finish executing.
		// Verify that the AfterFunc ran.
		cancel()
		synctest.Wait()
		fmt.Printf("after context is canceled:  afterFuncCalled=%v\n", afterFuncCalled)

		// Output:
		// before context is canceled: afterFuncCalled=false
		// after context is canceled:  afterFuncCalled=true
	})
}

// This example demonstrates testing the context.WithTimeout function.
//
// WithTimeout creates a context which is canceled after a timeout.
//
// The test verifies that the context is not canceled before the timeout expires,
// and is canceled after the timeout expires.
func Example_contextWithTimeout() {
	synctest.Run(func() {
		// Create a context.Context which is canceled after a timeout.
		const timeout = 5 * time.Second
		ctx, cancel := context.WithTimeout(context.Background(), timeout)
		defer cancel()

		// Wait just less than the timeout.
		time.Sleep(timeout - time.Nanosecond)
		synctest.Wait()
		fmt.Printf("before timeout: ctx.Err() = %v\n", ctx.Err())

		// Wait the rest of the way until the timeout.
		time.Sleep(time.Nanosecond)
		synctest.Wait()
		fmt.Printf("after timeout:  ctx.Err() = %v\n", ctx.Err())

		// Output:
		// before timeout: ctx.Err() = <nil>
		// after timeout:  ctx.Err() = context deadline exceeded
	})
}