Skip to content

Commit a3e8819

Browse files
committed
add code and tests
1 parent b75d1e6 commit a3e8819

File tree

3 files changed

+142
-9
lines changed

3 files changed

+142
-9
lines changed

behavioral/memento/README.md

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,47 @@
22

33
## Description
44

5-
The memento pattern provides the ability to restore an object to its previous
6-
state (undo via rollback). It is implemented with three elements:
5+
The memento pattern provides the ability to restore an object to of its
6+
previous state (undo via rollback). It is implemented with three elements:
77

8+
- memento
89
- originator
910
- caretaker
10-
- memento
11-
12-
The originator is an object that has an internal state. The caretaker change
13-
the originator's state, but wants to be able to undo the change. The caretaker
14-
first asks the originator for a memento object. Then it does whatever operation
15-
it was going to do. To roll back it returns the memento object to the
16-
originator.
1711

12+
The `memento` is an extra-layer not yet saved. The `originator` is a type in
13+
charge to build/create the mementos. Finally, the `caretaker` is the type that
14+
stores the lists of mementos.
1815

1916
## Implementation
2017

18+
Every time we create new memento object, its state is taken from the originator
19+
element of the design pattern.
20+
21+
```go
22+
func TestNewMementoTakeOriginatorState(t *testing.T) {
23+
firstState := originator{}
24+
firstState.state = State{Description: "Idle"}
25+
mem := firstState.NewMemento()
26+
if mem.state.Description != "Idle" {
27+
t.Error("Expected state was not found")
28+
}
29+
}
30+
31+
func (o *originator) NewMemento() memento {
32+
return memento{state: o.state}
33+
}
34+
```
35+
In the following test state is changed to "working" to ensure that new state
36+
will be written.
37+
38+
```go
39+
func TestStoresIdleState(t *testing.T) {
40+
originator := originator{state: State{"Idle"}}
41+
idleMemento := originator.NewMemento()
42+
originator.state.Description = "Working"
43+
originator.ExtractAndStoreState(idleMemento)
44+
if originator.state.Description != "Idle" {
45+
t.Error("Unexpected state found")
46+
}
47+
}
48+
```

behavioral/memento/memento.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
type State struct {
8+
Description string
9+
}
10+
11+
type memento struct {
12+
state State
13+
}
14+
15+
type originator struct {
16+
state State
17+
}
18+
19+
func (o *originator) NewMemento() memento {
20+
return memento{state: o.state}
21+
}
22+
23+
func (o *originator) ExtractAndStoreState(m memento) {
24+
o.state = m.state
25+
}
26+
27+
type careTaker struct {
28+
mementoList []memento
29+
}
30+
31+
func (c *careTaker) Add(m memento) {
32+
c.mementoList = append(c.mementoList, m)
33+
}
34+
35+
func (c *careTaker) Memento(i int) (memento, error) {
36+
if i < 0 {
37+
return memento{}, fmt.Errorf("Index not found")
38+
}
39+
return c.mementoList[i], nil
40+
}

behavioral/memento/memento_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestNewMementoTakeOriginatorState(t *testing.T) {
8+
firstState := originator{}
9+
firstState.state = State{Description: "Idle"}
10+
mem := firstState.NewMemento()
11+
if mem.state.Description != "Idle" {
12+
t.Error("Expected state was not found")
13+
}
14+
}
15+
16+
func TestCareTakerKeepAlMementoInsideAList(t *testing.T) {
17+
firstState := originator{}
18+
firstState.state = State{Description: "Idle"}
19+
mem := firstState.NewMemento()
20+
careTaker := careTaker{}
21+
lenBeforeAddedMemento := len(careTaker.mementoList)
22+
careTaker.Add(mem)
23+
if len(careTaker.mementoList) != lenBeforeAddedMemento+1 {
24+
t.Errorf("No new elements were added on the list")
25+
}
26+
}
27+
28+
func TestCareTaker(t *testing.T) {
29+
originator := originator{}
30+
careTaker := careTaker{}
31+
originator.state = State{"foo"}
32+
careTaker.Add(originator.NewMemento())
33+
mem, err := careTaker.Memento(0)
34+
if err != nil {
35+
t.Fatal(err)
36+
}
37+
if mem.state.Description != "foo" {
38+
t.Error("Unexpected state")
39+
}
40+
}
41+
42+
func TestCareTakerDetectIfNonExistentIndexIsRequested(t *testing.T) {
43+
originator := originator{}
44+
careTaker := careTaker{}
45+
originator.state = State{"foo"}
46+
careTaker.Add(originator.NewMemento())
47+
_, err := careTaker.Memento(0)
48+
if err != nil {
49+
t.Fatal(err)
50+
}
51+
_, err = careTaker.Memento(-1)
52+
if err == nil {
53+
t.Fatal("An error is expected")
54+
}
55+
}
56+
57+
func TestStoresIdleState(t *testing.T) {
58+
originator := originator{state: State{"Idle"}}
59+
idleMemento := originator.NewMemento()
60+
originator.state.Description = "Working"
61+
originator.ExtractAndStoreState(idleMemento)
62+
if originator.state.Description != "Idle" {
63+
t.Error("Unexpected state found")
64+
}
65+
}

0 commit comments

Comments
 (0)