}
 }
 
-func TestTimer(t *testing.T) {
+func TestTimerReadBeforeDeadline(t *testing.T) {
        synctest.Run(func() {
                start := time.Now()
                tm := time.NewTimer(5 * time.Second)
        })
 }
 
+func TestTimerReadAfterDeadline(t *testing.T) {
+       synctest.Run(func() {
+               delay := 1 * time.Second
+               want := time.Now().Add(delay)
+               tm := time.NewTimer(delay)
+               time.Sleep(2 * delay)
+               got := <-tm.C
+               if got != want {
+                       t.Errorf("<-tm.C = %v, want %v", got, want)
+               }
+       })
+}
+
+func TestTimerReset(t *testing.T) {
+       synctest.Run(func() {
+               start := time.Now()
+               tm := time.NewTimer(1 * time.Second)
+               if got, want := <-tm.C, start.Add(1*time.Second); got != want {
+                       t.Errorf("first sleep: <-tm.C = %v, want %v", got, want)
+               }
+
+               tm.Reset(2 * time.Second)
+               if got, want := <-tm.C, start.Add((1+2)*time.Second); got != want {
+                       t.Errorf("second sleep: <-tm.C = %v, want %v", got, want)
+               }
+
+               tm.Reset(3 * time.Second)
+               time.Sleep(1 * time.Second)
+               tm.Reset(3 * time.Second)
+               if got, want := <-tm.C, start.Add((1+2+4)*time.Second); got != want {
+                       t.Errorf("third sleep: <-tm.C = %v, want %v", got, want)
+               }
+       })
+}
+
 func TestTimeAfter(t *testing.T) {
        synctest.Run(func() {
                i := 0
 func TestTimerFromOutsideBubble(t *testing.T) {
        tm := time.NewTimer(10 * time.Millisecond)
        synctest.Run(func() {
-               defer wantPanic(t, "timer moved between synctest groups")
                <-tm.C
        })
+       if tm.Stop() {
+               t.Errorf("synctest.Run unexpectedly returned before timer fired")
+       }
 }
 
 func TestChannelFromOutsideBubble(t *testing.T) {
 
 // to send a value to its associated channel. If so, it does.
 // The timer must not be locked.
 func (t *timer) maybeRunChan() {
-       if sg := getg().syncGroup; sg != nil || t.isFake {
+       if t.isFake {
                t.lock()
                var timerGroup *synctestGroup
                if t.ts != nil {
                        timerGroup = t.ts.syncGroup
                }
                t.unlock()
-               if sg == nil || !t.isFake || sg != timerGroup {
-                       panic(plainError("timer moved between synctest groups"))
+               sg := getg().syncGroup
+               if sg == nil {
+                       panic(plainError("synctest timer accessed from outside bubble"))
+               }
+               if timerGroup != nil && sg != timerGroup {
+                       panic(plainError("timer moved between synctest bubbles"))
                }
                // No need to do anything here.
                // synctest.Run will run the timer when it advances its fake clock.