├── .gitignore ├── LICENSE ├── README.md ├── cargo ├── app │ └── service │ │ └── cargo_api.go ├── domain │ ├── model │ │ ├── base │ │ │ ├── aggregate_root.go │ │ │ ├── entity.go │ │ │ └── value_object.go │ │ ├── cargo.go │ │ ├── cargo_factory.go │ │ ├── cargo_provider.go │ │ ├── cargo_repo.go │ │ └── delivery.go │ └── service │ │ └── cargo_service.go ├── infra │ ├── cargo_provider_impl.go │ └── cargo_repo_impl.go └── test │ └── cargo_test.go ├── counting-shapes ├── app │ └── service │ │ └── counting_shapes.go ├── domain │ ├── model │ │ ├── set.go │ │ ├── set_test.go │ │ └── spec.go │ └── service │ │ └── counting_shapes.go └── test │ └── counting_shapes_test.go └── shapes.png /.gitignore: -------------------------------------------------------------------------------- 1 | # temp 2 | tmp/ 3 | output/ 4 | build/ 5 | 6 | # mac 7 | .DS_Store 8 | 9 | # python 10 | *.pyc 11 | 12 | # clion 13 | .idea/ 14 | *.xml 15 | 16 | # eclipse 17 | .settings/ 18 | .project 19 | .cproject 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Zhang Xiaolong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DDD sample 2 | 3 | 4 | ### cargo 5 | 6 | DDD sample with OO 7 | 8 | ## counting shapes 9 | 10 | DDD sample with FP 11 | 12 | 13 | 14 | The first game: 15 | >How many triangles can you see?
24, details as follows:
[abc abd abe acd ace ade aef aeg aeh afg afh agh ahi ahj ahk aij aik ajk beh ceg def ehk fhj ghi] 16 | 17 | The second game: 18 | >How many quadrangles can you see?
18, details as follows:
[aceh adeg adeh afhk aghj aghk bcgh bcih bdfh bdjh bekh cdfg cdji ceki dekj efjk egik fgij] 19 | -------------------------------------------------------------------------------- /cargo/app/service/cargo_api.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/agiledragon/ddd-sample-in-golang/cargo/domain/service" 5 | ) 6 | 7 | func CreateCargo(cargoId string, afterDays uint) { 8 | service.GetCargoService().Create(cargoId, afterDays) 9 | } 10 | 11 | func DelayCargo(cargoId string, days uint) { 12 | service.GetCargoService().Delay(cargoId, days) 13 | } 14 | 15 | func GetCargoAfterDays(cargoId string) uint { 16 | return service.GetCargoService().GetAfterDays(cargoId) 17 | } 18 | 19 | func DestroyCargo(cargoId string) { 20 | service.GetCargoService().DestroyCargo(cargoId) 21 | } 22 | -------------------------------------------------------------------------------- /cargo/domain/model/base/aggregate_root.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | type AggregateRoot struct { 4 | Entity 5 | } 6 | 7 | func NewAggregateRoot(id string) AggregateRoot { 8 | return AggregateRoot{NewEntity(id)} 9 | } 10 | -------------------------------------------------------------------------------- /cargo/domain/model/base/entity.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | type Entity struct { 4 | id string 5 | } 6 | 7 | func NewEntity(id string) Entity { 8 | return Entity{id: id} 9 | } 10 | 11 | func (this *Entity) Id() string { 12 | return this.id 13 | } 14 | 15 | func (this *Entity) Equal(other *Entity) bool { 16 | return this.id == other.id 17 | } 18 | 19 | func (this *Entity) NotEqual(other *Entity) bool { 20 | return !this.Equal(other) 21 | } 22 | -------------------------------------------------------------------------------- /cargo/domain/model/base/value_object.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | type ValueObject struct { 4 | } 5 | -------------------------------------------------------------------------------- /cargo/domain/model/cargo.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/agiledragon/ddd-sample-in-golang/cargo/domain/model/base" 5 | ) 6 | 7 | type Cargo struct { 8 | base.AggregateRoot 9 | Delivery Delivery 10 | } 11 | 12 | func newCargo(cargoId string, delivery Delivery) *Cargo { 13 | return &Cargo{AggregateRoot: base.NewAggregateRoot(cargoId), Delivery: delivery} 14 | } 15 | 16 | func (this *Cargo) Delay(days uint) { 17 | afterDays := this.GetAfterDays() + days 18 | this.Delivery = Delivery{AfterDays: afterDays} 19 | } 20 | 21 | func (this *Cargo) GetAfterDays() uint { 22 | return this.Delivery.AfterDays 23 | } 24 | -------------------------------------------------------------------------------- /cargo/domain/model/cargo_factory.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type CargoFactory struct { 4 | } 5 | 6 | func (this CargoFactory) Create(cargoId string, afterDays uint) *Cargo { 7 | delivery := Delivery{AfterDays: afterDays} 8 | return newCargo(cargoId, delivery) 9 | } 10 | -------------------------------------------------------------------------------- /cargo/domain/model/cargo_provider.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type CargoProvider interface { 4 | Confirm(cargo *Cargo) 5 | } 6 | 7 | var p CargoProvider = nil 8 | 9 | func SetCargoProvider(provider CargoProvider) { 10 | p = provider 11 | } 12 | 13 | func GetCargoProvider() CargoProvider { 14 | return p 15 | } 16 | -------------------------------------------------------------------------------- /cargo/domain/model/cargo_repo.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type CargoRepo interface { 4 | Add(cargo *Cargo) 5 | Get(cargoId string) *Cargo 6 | Update(cargo *Cargo) 7 | Remove(cargoId string) 8 | } 9 | 10 | var r CargoRepo = nil 11 | 12 | func SetCargoRepo(repo CargoRepo) { 13 | r = repo 14 | } 15 | 16 | func GetCargoRepo() CargoRepo { 17 | return r 18 | } 19 | -------------------------------------------------------------------------------- /cargo/domain/model/delivery.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/agiledragon/ddd-sample-in-golang/cargo/domain/model/base" 5 | ) 6 | 7 | type Delivery struct { 8 | base.ValueObject 9 | AfterDays uint 10 | } 11 | -------------------------------------------------------------------------------- /cargo/domain/service/cargo_service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/agiledragon/ddd-sample-in-golang/cargo/domain/model" 5 | "sync" 6 | ) 7 | 8 | type CargoService struct { 9 | repo model.CargoRepo 10 | provider model.CargoProvider 11 | } 12 | 13 | var cs = &CargoService{} 14 | var once sync.Once 15 | 16 | func GetCargoService() *CargoService { 17 | once.Do(func() { 18 | cs.repo = model.GetCargoRepo() 19 | cs.provider = model.GetCargoProvider() 20 | }) 21 | return cs 22 | } 23 | 24 | func (this *CargoService) Create(cargoId string, afterDays uint) { 25 | cargo := model.CargoFactory{}.Create(cargoId, afterDays) 26 | this.repo.Add(cargo) 27 | this.provider.Confirm(cargo) 28 | } 29 | 30 | func (this *CargoService) Delay(cargoId string, days uint) { 31 | cargo := this.repo.Get(cargoId) 32 | if cargo == nil { 33 | panic("not found cargo by cargoId") 34 | } 35 | cargo.Delay(days) 36 | this.repo.Update(cargo) 37 | this.provider.Confirm(cargo) 38 | } 39 | 40 | func (this *CargoService) GetAfterDays(cargoId string) uint { 41 | cargo := this.repo.Get(cargoId) 42 | if cargo == nil { 43 | panic("not found cargo by cargoId") 44 | } 45 | return cargo.GetAfterDays() 46 | } 47 | 48 | func (this *CargoService) DestroyCargo(cargoId string) { 49 | this.repo.Remove(cargoId) 50 | } 51 | -------------------------------------------------------------------------------- /cargo/infra/cargo_provider_impl.go: -------------------------------------------------------------------------------- 1 | package infra 2 | 3 | import "github.com/agiledragon/ddd-sample-in-golang/cargo/domain/model" 4 | 5 | type CargoProviderImpl struct { 6 | } 7 | 8 | func (this *CargoProviderImpl) Confirm(cargo *model.Cargo) { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /cargo/infra/cargo_repo_impl.go: -------------------------------------------------------------------------------- 1 | package infra 2 | 3 | import "github.com/agiledragon/ddd-sample-in-golang/cargo/domain/model" 4 | 5 | type CargoRepoImpl struct { 6 | } 7 | 8 | func (this *CargoRepoImpl) Add(cargo *model.Cargo) { 9 | 10 | } 11 | 12 | func (this *CargoRepoImpl) Get(cargoId string) *model.Cargo { 13 | return nil 14 | } 15 | 16 | func (this *CargoRepoImpl) Update(cargo *model.Cargo) { 17 | 18 | } 19 | 20 | func (this *CargoRepoImpl) Remove(CargoId string) { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /cargo/test/cargo_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/agiledragon/ddd-sample-in-golang/cargo/app/service" 5 | "github.com/agiledragon/ddd-sample-in-golang/cargo/domain/model" 6 | . "github.com/smartystreets/goconvey/convey" 7 | "testing" 8 | ) 9 | 10 | type SpyCargoProvider struct { 11 | cargoId string 12 | afterDays uint 13 | } 14 | 15 | func (this *SpyCargoProvider) Confirm(cargo *model.Cargo) { 16 | this.cargoId = cargo.Id() 17 | this.afterDays = cargo.GetAfterDays() 18 | } 19 | 20 | type FakeCargoRepo struct { 21 | cargoes map[string]*model.Cargo 22 | } 23 | 24 | func (this *FakeCargoRepo) Add(cargo *model.Cargo) { 25 | this.cargoes[cargo.Id()] = cargo 26 | } 27 | 28 | func (this *FakeCargoRepo) Get(cargoId string) *model.Cargo { 29 | return this.cargoes[cargoId] 30 | } 31 | 32 | func (this *FakeCargoRepo) Update(cargo *model.Cargo) { 33 | this.cargoes[cargo.Id()] = cargo 34 | } 35 | 36 | func (this *FakeCargoRepo) Remove(cargoId string) { 37 | delete(this.cargoes, cargoId) 38 | } 39 | 40 | func TestCargo(t *testing.T) { 41 | provider := &SpyCargoProvider{} 42 | model.SetCargoProvider(provider) 43 | repo := &FakeCargoRepo{make(map[string]*model.Cargo)} 44 | model.SetCargoRepo(repo) 45 | const cargoId = "1" 46 | 47 | Convey("TestCargo", t, func() { 48 | 49 | Convey("create cargo", func() { 50 | const afterDays = 10 51 | service.CreateCargo(cargoId, afterDays) 52 | So(provider.cargoId, ShouldEqual, cargoId) 53 | So(provider.afterDays, ShouldEqual, afterDays) 54 | So(service.GetCargoAfterDays(cargoId), ShouldEqual, afterDays) 55 | service.DestroyCargo(cargoId) 56 | }) 57 | 58 | Convey("delay cargo", func() { 59 | const afterDays = 20 60 | const days = 5 61 | service.CreateCargo(cargoId, afterDays) 62 | service.DelayCargo(cargoId, days) 63 | So(provider.cargoId, ShouldEqual, cargoId) 64 | So(provider.afterDays, ShouldEqual, afterDays+days) 65 | So(service.GetCargoAfterDays(cargoId), ShouldEqual, afterDays+days) 66 | service.DestroyCargo(cargoId) 67 | }) 68 | }) 69 | } 70 | -------------------------------------------------------------------------------- /counting-shapes/app/service/counting_shapes.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/agiledragon/ddd-sample-in-golang/counting-shapes/domain/service" 5 | ) 6 | 7 | func CountingTriangles(points string, lines []string) int { 8 | return len(service.CountingTriangles(points, lines)) 9 | } 10 | 11 | func CountingQuadrangles(points string, lines []string) int { 12 | return len(service.CountingQuadrangles(points, lines)) 13 | } -------------------------------------------------------------------------------- /counting-shapes/domain/model/set.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "strings" 5 | //"fmt" 6 | ) 7 | 8 | type Point = byte 9 | type Line = string 10 | type Points = string 11 | 12 | 13 | func belong(points Points, lines []Line) bool { 14 | flag := false 15 | for _, line := range lines { 16 | flag = true 17 | for _, point := range points { 18 | if !strings.ContainsRune(line, point) { 19 | flag = false 20 | break 21 | } 22 | } 23 | if flag { 24 | return true 25 | } 26 | } 27 | return false 28 | } 29 | 30 | func Subset(points Points, n int) []Points { 31 | l := len(points) 32 | if l < n { 33 | return nil 34 | } 35 | if l == n { 36 | return []string{points} 37 | } 38 | 39 | results := make([]Points, 0) 40 | if n == 1 { 41 | for i := range points { 42 | results = append(results, Points([]byte{points[i]})) 43 | } 44 | return results 45 | } 46 | 47 | firsts := Subset(points[1:], n - 1) 48 | for _, first := range firsts { 49 | results = append(results, Points([]byte{points[0]}) + first) 50 | } 51 | 52 | lasts := Subset(points[1:], n) 53 | results = append(results, lasts...) 54 | 55 | return results 56 | } 57 | 58 | func hasConnected(lines []Line) func(x, y Point) bool { 59 | return func(x, y Point) bool { 60 | points := make([]Point, 2) 61 | points[0] = x 62 | points[1] = y 63 | return belong(Points(points), lines) 64 | } 65 | } 66 | 67 | func inSameLine(lines []Line) func(x, y, z Point) bool { 68 | return func(x, y, z Point) bool { 69 | points := make([]Point, 3) 70 | points[0] = x 71 | points[1] = y 72 | points[2] = z 73 | return belong(Points(points), lines) 74 | } 75 | } 76 | 77 | func not(flag bool) bool { 78 | return !flag 79 | } 80 | 81 | func ringOrderConnected(lines []Line) func(points ...Point) bool { 82 | connected := hasConnected(lines) 83 | 84 | return func(points ...Point) bool { 85 | // fmt.Println("ring:", points) 86 | prev := points[0] 87 | for i := 1; i < len(points); i++ { 88 | next := points[i] 89 | if !connected(prev, next) { 90 | return false 91 | } 92 | prev = next 93 | } 94 | first := points[0] 95 | last := points[len(points) - 1] 96 | if connected(last, first) { 97 | return true 98 | } 99 | return false 100 | } 101 | } 102 | 103 | func hasCrossConnected(lines []Line) func(ls, rs Points) bool { 104 | return func(ls, rs Points) bool { 105 | flag := false 106 | lfound := false 107 | rfound := false 108 | ll := "" 109 | rl := "" 110 | for _, line := range lines { 111 | if !lfound { 112 | flag = true 113 | for _, l := range ls { 114 | if !strings.ContainsRune(line, l) { 115 | flag = false 116 | break 117 | } 118 | } 119 | if flag { 120 | ll = line 121 | lfound = true 122 | } 123 | } 124 | 125 | if !rfound { 126 | flag = true 127 | for _, r := range rs { 128 | if !strings.ContainsRune(line, r) { 129 | flag = false 130 | break 131 | } 132 | } 133 | if flag { 134 | rl = line 135 | rfound = true 136 | } 137 | } 138 | 139 | if lfound && rfound { 140 | break 141 | } 142 | 143 | } 144 | 145 | //fmt.Println("ll:", ll) 146 | //fmt.Println("rl:", rl) 147 | 148 | lstart := 0 149 | lend := 0 150 | for i := range ll { 151 | if ll[i] == ls[0] { 152 | lstart = i 153 | } else if ll[i] == ls[1] { 154 | lend = i 155 | } 156 | } 157 | if lstart > lend { 158 | lstart, lend = lend, lstart 159 | } 160 | //fmt.Println("lstart, lend:", lstart, lend) 161 | 162 | 163 | rstart := 0 164 | rend := 0 165 | for i := range rl { 166 | if rl[i] == rs[0] { 167 | rstart = i 168 | } else if rl[i] == rs[1] { 169 | rend = i 170 | } 171 | } 172 | if rstart > rend { 173 | rstart, rend = rend, rstart 174 | } 175 | //fmt.Println("rstart, rend:", rstart, rend) 176 | for i := 1; i < lend - lstart; i++ { 177 | for j := 1; j < rend - rstart; j++ { 178 | //fmt.Println("ll[i]:", ll[lstart + i]) 179 | //fmt.Println("rl[j]:", rl[rstart + j]) 180 | if ll[lstart + i] == rl[rstart + j] { 181 | return true 182 | } 183 | } 184 | } 185 | return false 186 | } 187 | } -------------------------------------------------------------------------------- /counting-shapes/domain/model/set_test.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | . "github.com/smartystreets/goconvey/convey" 5 | "testing" 6 | ) 7 | 8 | func TestRingConnected(t *testing.T) { 9 | lines := []string{"abh", "acgi", "adfj", "aek", "bcde", "hgfe", "hijk"} 10 | ring_connected := ringOrderConnected(lines) 11 | Convey("TestRingConnected", t, func() { 12 | 13 | Convey("succ", func() { 14 | So(ring_connected([]Point("abc")...), ShouldBeTrue) 15 | So(ring_connected([]Point("bcgh")...), ShouldBeTrue) 16 | So(ring_connected([]Point("cdfg")...), ShouldBeTrue) 17 | So(ring_connected([]Point("abeg")...), ShouldBeTrue) 18 | So(ring_connected([]Point("abhg")...), ShouldBeTrue) 19 | So(ring_connected([]Point("defj")...), ShouldBeTrue) 20 | }) 21 | 22 | Convey("failed", func() { 23 | So(ring_connected([]Point("acf")...), ShouldBeFalse) 24 | So(ring_connected([]Point("bcg")...), ShouldBeFalse) 25 | So(ring_connected([]Point("defk")...), ShouldBeFalse) 26 | }) 27 | 28 | }) 29 | } 30 | 31 | func TestHasCrossConnected(t *testing.T) { 32 | lines := []string{"abh", "acgi", "adfj", "aek", "bcde", "hgfe", "hijk"} 33 | cross_connected := hasCrossConnected(lines) 34 | Convey("TestHasCrossConnected", t, func() { 35 | 36 | Convey("succ", func() { 37 | So(cross_connected("ag", "bd"), ShouldBeTrue) 38 | So(cross_connected("af", "ce"), ShouldBeTrue) 39 | So(cross_connected("af", "be"), ShouldBeTrue) 40 | So(cross_connected("ai", "eh"), ShouldBeTrue) 41 | }) 42 | 43 | Convey("failed", func() { 44 | So(cross_connected("bc", "hg"), ShouldBeFalse) 45 | So(cross_connected("fj", "ek"), ShouldBeFalse) 46 | }) 47 | 48 | }) 49 | } 50 | 51 | -------------------------------------------------------------------------------- /counting-shapes/domain/model/spec.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | func IsTriangle(points Points, lines []Line) bool { 4 | ring_order_connected := ringOrderConnected(lines) 5 | in_same_line := inSameLine(lines) 6 | 7 | a := points[0] 8 | b := points[1] 9 | c := points[2] 10 | 11 | return ring_order_connected(a, b, c) && 12 | not(in_same_line(a, b, c)) 13 | } 14 | 15 | func IsQuadrangle(points Points, lines []Line) bool { 16 | ring_order_connected := ringOrderConnected(lines) 17 | cross_connected := hasCrossConnected(lines) 18 | in_same_line := inSameLine(lines) 19 | 20 | a := points[0] 21 | b := points[1] 22 | c := points[2] 23 | d := points[3] 24 | ab := Points([]Point{a, b}) 25 | cd := Points([]Point{c, d}) 26 | ad := Points([]Point{a, d}) 27 | bc := Points([]Point{b, c}) 28 | 29 | return ring_order_connected(a, b, c, d) && 30 | not(cross_connected(ab, cd)) && 31 | not(cross_connected(ad, bc)) && 32 | not(in_same_line(a, b, c)) && 33 | not(in_same_line(a, b, d)) && 34 | not(in_same_line(a, c, d)) && 35 | not(in_same_line(b, c, d)) 36 | } 37 | 38 | -------------------------------------------------------------------------------- /counting-shapes/domain/service/counting_shapes.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/agiledragon/ddd-sample-in-golang/counting-shapes/domain/model" 5 | // "fmt" 6 | "fmt" 7 | ) 8 | 9 | func CountingTriangles(points model.Points, lines []model.Line) []model.Points { 10 | sets := model.Subset(points, 3) 11 | matches := make([]model.Points, 0) 12 | for _, set := range sets { 13 | if model.IsTriangle(set, lines) { 14 | matches = append(matches, set) 15 | } 16 | } 17 | fmt.Println("matches:", matches) 18 | return matches 19 | } 20 | 21 | func CountingQuadrangles(points model.Points, lines []model.Line) []model.Points { 22 | sets := model.Subset(points, 4) 23 | matches := make([]model.Points, 0) 24 | for _, set := range sets { 25 | a := set[0] 26 | b := set[1] 27 | c := set[2] 28 | d := set[3] 29 | orderSets := []model.Points{ 30 | model.Points([]model.Point{a, b, c, d}), 31 | model.Points([]model.Point{a, b, d, c}), 32 | model.Points([]model.Point{a, c, b, d}), 33 | model.Points([]model.Point{a, c, d, b}), 34 | model.Points([]model.Point{a, d, b, c}), 35 | model.Points([]model.Point{a, d, c, b}), 36 | } 37 | 38 | for _, orderSet := range orderSets { 39 | if model.IsQuadrangle(orderSet, lines) { 40 | matches = append(matches, orderSet) 41 | break 42 | } 43 | } 44 | 45 | } 46 | //fmt.Println("matches:", matches) 47 | return matches 48 | } -------------------------------------------------------------------------------- /counting-shapes/test/counting_shapes_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | . "github.com/smartystreets/goconvey/convey" 5 | "testing" 6 | "github.com/agiledragon/ddd-sample-in-golang/counting-shapes/app/service" 7 | ) 8 | 9 | func TestCountingShapes(t *testing.T) { 10 | points := "abcdefghijk" 11 | lines := []string{"abh", "acgi", "adfj", "aek", "bcde", "hgfe", "hijk"} 12 | 13 | Convey("TestCountingShapes", t, func() { 14 | 15 | Convey("counting triangles", func() { 16 | num := service.CountingTriangles(points, lines) 17 | So(num, ShouldEqual, 24) 18 | }) 19 | 20 | Convey("counting quadrangles", func() { 21 | num := service.CountingQuadrangles(points, lines) 22 | So(num, ShouldEqual, 18) 23 | }) 24 | }) 25 | } 26 | 27 | -------------------------------------------------------------------------------- /shapes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agiledragon/ddd-sample-in-golang/c1f10a224a2a45ac9dbfa77eee05e8e0dab4596b/shapes.png --------------------------------------------------------------------------------