1Structural equality library for Golang. 2 3## Story 4 5While we were working on [HappyPancake](http://abdullin.com/happypancake/) project, [Pieter](https://twitter.com/pjvds) always wanted to have a better assertion library for our event-driven specifications. 6 7Months later, awesome folks from [@DDDBE](https://twitter.com/dddbe) community presented me with some Trappist Beer. Thanks to it (and some spare time on the weekend), this assertion library was finally written. 8 9## How it works 10 11You can define expectations on objects (e.g. API responses or expected events) by creating an instance of `seq.Map`, which is provided by the package `github.com/abdullin/seq`. 12 13Maps can be nested or they could have flat paths. Values could be represented with strings, primitive types, instances of `seq.Map` or JSON-serializable objects. 14 15Consider following types: 16 17```go 18type Robot struct { 19 Legs int `json:"legs"` 20 Arms int `json:"arms"` 21 Name string `json:"name"` 22} 23 24type Party struct { 25 Rating []int `json:"rating"` 26 Seating map[string]*Robot `json:"seating"` 27} 28``` 29Let's imagine that our JSON API returns `Party` object, which we want to verify. We could define our expectation like this: 30 31```go 32 expect := seq.Map{ 33 // array 34 "rating.len": 3, 35 "rating[1]": 5, 36 // flat path with value terminator 37 "seating.front.name": "R2D2", 38 "seating.front.arms": "1", 39 "seating.front.legs": 3, 40 // flat path with map terminator 41 "seating.right": seq.Map{ 42 "name": "C3PO", 43 }, 44 // flat path with object terminator 45 "seating.back": &Robot{ 46 Name: "Marvin", 47 Legs: 2, 48 Arms: 2, 49 }, 50 } 51 52``` 53Once you have the expectation, you could compare it with an actual object. Here is an example of a valid object: 54```go 55 actual := &Party{ 56 Rating: []int{4, 5, 4}, 57 Seating: map[string]*Robot{ 58 "front": &Robot{ 59 Name: "R2D2", 60 Arms: 1, 61 Legs: 3, 62 }, 63 "back": &Robot{ 64 Name: "Marvin", 65 Legs: 2, 66 Arms: 2, 67 }, 68 "right": &Robot{ 69 Name: "C3PO", 70 Legs: 2, 71 Arms: 2, 72 }, 73 }, 74 } 75 result := expect.Test(actual) 76 77``` 78Result value would contain `Issues []seq.Issue` with any differences and could be checked like this: 79 80```go 81if !result.Ok() { 82 fmt.Println("Differences") 83 for _, v := range result.Issues { 84 fmt.Println(v.String()) 85 } 86} 87``` 88 89If actual object has some invalid or missing properties, then result will have nice error messages. Consider this object: 90 91```go 92 actual := &Party{ 93 Seating: map[string]*Robot{ 94 "front": &Robot{ 95 Name: "R2D2", 96 Arms: 1, 97 }, 98 "back": &Robot{ 99 Name: "Marvin", 100 Arms: 3, 101 }, 102 "right": &Robot{ 103 Name: "C4PO", 104 Legs: 2, 105 Arms: 3, 106 }, 107 }, 108 } 109 110``` 111 112If verified against the original expectation, `result.Issues` would contain these error messages: 113 114``` 115Expected rating.len to be '3' but got nothing 116Expected seating.back.legs to be '2' but got '0' 117Expected seating.front.legs to be '3' but got '0' 118Expected rating[1] to be '5' but got nothing 119Expected seating.back.arms to be '2' but got '3' 120Expected seating.right.name to be 'C3PO' but got 'C4PO' 121``` 122Check out the [unit tests](https://github.com/abdullin/seq/blob/master/seq_test.go) for more examples. 123 124## Feedback 125 126Feedback is welcome and appreciated! 127