1// Copyright 2018 The Wire Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// This test demonstrates how to use mocks with wire.
16
17package main
18
19import (
20	"fmt"
21	"time"
22
23	"github.com/google/wire"
24)
25
26func main() {
27	// Create a "real" greeter.
28	// Greet() will include the real current time, so elide it for repeatable
29	// tests.
30	fmt.Printf("Real time greeting: %s [current time elided]\n", initApp().Greet()[0:15])
31
32	// There are two approaches for creating an app with mocks.
33
34	// Approach A: create the mocks manually, and pass them to an injector.
35	// This approach is useful if you need to prime the mocks beforehand.
36	fmt.Println("Approach A")
37	mt := newMockTimer()
38	mockedApp := initMockedAppFromArgs(mt)
39	fmt.Println(mockedApp.Greet()) // prints greeting with time = zero time
40	mt.T = mt.T.AddDate(1999, 0, 0)
41	fmt.Println(mockedApp.Greet()) // prints greeting with time = year 2000
42
43	// Approach B: allow the injector to create the mocks, and return a struct
44	// that includes the resulting app plus the mocks.
45	fmt.Println("Approach B")
46	appWithMocks := initMockedApp()
47	fmt.Println(appWithMocks.app.Greet()) // prints greeting with time = zero time
48	appWithMocks.mt.T = appWithMocks.mt.T.AddDate(999, 0, 0)
49	fmt.Println(appWithMocks.app.Greet()) // prints greeting with time = year 1000
50}
51
52// appSet is a provider set for creating a real app.
53var appSet = wire.NewSet(
54	wire.Struct(new(app), "*"),
55	wire.Struct(new(greeter), "*"),
56	wire.InterfaceValue(new(timer), realTime{}),
57)
58
59// appSetWithoutMocks is a provider set for creating an app with mocked
60// dependencies. The mocked dependencies are omitted and must be provided as
61// arguments to the injector.
62// It is used for Approach A.
63var appSetWithoutMocks = wire.NewSet(
64	wire.Struct(new(app), "*"),
65	wire.Struct(new(greeter), "*"),
66)
67
68// mockAppSet is a provider set for creating a mocked app, including the mocked
69// dependencies.
70// It is used for Approach B.
71var mockAppSet = wire.NewSet(
72	wire.Struct(new(app), "*"),
73	wire.Struct(new(greeter), "*"),
74	wire.Struct(new(appWithMocks), "*"),
75	// For each mocked dependency, add a provider and use wire.Bind to bind
76	// the concrete type to the relevant interface.
77	newMockTimer,
78	wire.Bind(new(timer), new(*mockTimer)),
79)
80
81type timer interface {
82	Now() time.Time
83}
84
85// realTime implements timer with the real time.
86type realTime struct{}
87
88func (realTime) Now() time.Time { return time.Now() }
89
90// mockTimer implements timer using a mocked time.
91type mockTimer struct {
92	T time.Time
93}
94
95func newMockTimer() *mockTimer      { return &mockTimer{} }
96func (m *mockTimer) Now() time.Time { return m.T }
97
98// greeter issues greetings with the time provided by T.
99type greeter struct {
100	T timer
101}
102
103func (g greeter) Greet() string {
104	return fmt.Sprintf("Good day! It is %v", g.T.Now())
105}
106
107type app struct {
108	g greeter
109}
110
111func (a app) Greet() string {
112	return a.g.Greet()
113}
114
115// appWithMocks is used for Approach B, to return the app plus its mocked
116// dependencies.
117type appWithMocks struct {
118	app app
119	mt  *mockTimer
120}
121