~juju-qa/ubuntu/yakkety/juju/2.0-beta17

« back to all changes in this revision

Viewing changes to src/gopkg.in/juju/jujusvg.v1/canvas_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-08-26 19:28:00 UTC
  • mfrom: (1.5.1)
  • Revision ID: nicholas.skaggs@canonical.com-20160826192800-b2rgj3da7tgfdca4
* New upstream release 2.0-beta16
* Remove all quilt patches
* Ensure autopkgtests run on LXD upload (LP: #1614724)
* Update debian/copyrights

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package jujusvg
2
 
 
3
 
import (
4
 
        "bytes"
5
 
        "encoding/xml"
6
 
        "image"
7
 
        "io"
8
 
 
9
 
        "github.com/ajstarks/svgo"
10
 
        jc "github.com/juju/testing/checkers"
11
 
        gc "gopkg.in/check.v1"
12
 
 
13
 
        "gopkg.in/juju/jujusvg.v1/assets"
14
 
)
15
 
 
16
 
type CanvasSuite struct{}
17
 
 
18
 
var _ = gc.Suite(&CanvasSuite{})
19
 
 
20
 
func (s *CanvasSuite) TestApplicationRender(c *gc.C) {
21
 
        // Ensure that the Application's definition and usage methods output the
22
 
        // proper SVG elements.
23
 
        var tests = []struct {
24
 
                about       string
25
 
                application application
26
 
                expected    string
27
 
        }{
28
 
                {
29
 
                        about: "Application without iconSrc, no def created",
30
 
                        application: application{
31
 
                                name: "foo",
32
 
                                point: image.Point{
33
 
                                        X: 0,
34
 
                                        Y: 0,
35
 
                                },
36
 
                                iconUrl: "foo",
37
 
                        },
38
 
                        expected: `<g transform="translate(0,0)" >
39
 
<title>foo</title>
40
 
<circle cx="90" cy="90" r="90" class="application-block" fill="#f5f5f5" stroke="#888" stroke-width="1" />
41
 
<image x="42" y="42" width="96" height="96" xlink:href="foo" clip-path="url(#clip-mask)" />
42
 
<rect x="0" y="135" width="180" height="32" rx="2" ry="2" fill="rgba(220, 220, 220, 0.8)" />
43
 
<text x="90" y="157" text-anchor="middle" style="font-weight:200" >foo</text>
44
 
</g>
45
 
`,
46
 
                },
47
 
                {
48
 
                        about: "Application with iconSrc",
49
 
                        application: application{
50
 
                                name:      "bar",
51
 
                                charmPath: "bar",
52
 
                                point: image.Point{
53
 
                                        X: 0,
54
 
                                        Y: 0,
55
 
                                },
56
 
                                iconSrc: []byte("<svg>bar</svg>"),
57
 
                        },
58
 
                        expected: `<svg:svg xmlns:svg="http://www.w3.org/2000/svg" id="icon-1">bar</svg:svg><g transform="translate(0,0)" >
59
 
<title>bar</title>
60
 
<circle cx="90" cy="90" r="90" class="application-block" fill="#f5f5f5" stroke="#888" stroke-width="1" />
61
 
<use x="0" y="0" xlink:href="#icon-1" transform="translate(42,42)" width="96" height="96" clip-path="url(#clip-mask)" />
62
 
<rect x="0" y="135" width="180" height="32" rx="2" ry="2" fill="rgba(220, 220, 220, 0.8)" />
63
 
<text x="90" y="157" text-anchor="middle" style="font-weight:200" >bar</text>
64
 
</g>
65
 
`,
66
 
                },
67
 
                {
68
 
                        about: "Application with already def'd icon",
69
 
                        application: application{
70
 
                                name:      "baz",
71
 
                                charmPath: "bar",
72
 
                                point: image.Point{
73
 
                                        X: 0,
74
 
                                        Y: 0,
75
 
                                },
76
 
                                iconSrc: []byte("<svg>bar</svg>"),
77
 
                        },
78
 
                        expected: `<g transform="translate(0,0)" >
79
 
<title>baz</title>
80
 
<circle cx="90" cy="90" r="90" class="application-block" fill="#f5f5f5" stroke="#888" stroke-width="1" />
81
 
<use x="0" y="0" xlink:href="#icon-1" transform="translate(42,42)" width="96" height="96" clip-path="url(#clip-mask)" />
82
 
<rect x="0" y="135" width="180" height="32" rx="2" ry="2" fill="rgba(220, 220, 220, 0.8)" />
83
 
<text x="90" y="157" text-anchor="middle" style="font-weight:200" >baz</text>
84
 
</g>
85
 
`,
86
 
                },
87
 
        }
88
 
        // Maintain our list of rendered icons outside the loop.
89
 
        iconsRendered := make(map[string]bool)
90
 
        iconIds := make(map[string]string)
91
 
        for _, test := range tests {
92
 
                var buf bytes.Buffer
93
 
                svg := svg.New(&buf)
94
 
                test.application.definition(svg, iconsRendered, iconIds)
95
 
                test.application.usage(svg, iconIds)
96
 
                c.Log(test.about)
97
 
                c.Log(buf.String())
98
 
                c.Assert(buf.String(), gc.Equals, test.expected)
99
 
        }
100
 
}
101
 
 
102
 
func (s *CanvasSuite) TestRelationRender(c *gc.C) {
103
 
        // Ensure that the Relation's definition and usage methods output the
104
 
        // proper SVG elements.
105
 
        var buf bytes.Buffer
106
 
        svg := svg.New(&buf)
107
 
        relation := applicationRelation{
108
 
                name: "foo",
109
 
                applicationA: &application{
110
 
                        point: image.Point{
111
 
                                X: 0,
112
 
                                Y: 0,
113
 
                        },
114
 
                },
115
 
                applicationB: &application{
116
 
                        point: image.Point{
117
 
                                X: 100,
118
 
                                Y: 100,
119
 
                        },
120
 
                },
121
 
        }
122
 
        relation.definition(svg)
123
 
        relation.usage(svg)
124
 
        c.Assert(buf.String(), gc.Equals,
125
 
                `<g >
126
 
<title>foo</title>
127
 
<line x1="90" y1="90" x2="190" y2="190" stroke="#a7a7a7" stroke-width="1px" stroke-dasharray="62.71, 16" />
128
 
<use x="132" y="132" xlink:href="#healthCircle" />
129
 
<circle cx="153" cy="153" r="4" fill="#a7a7a7" />
130
 
<circle cx="126" cy="126" r="4" fill="#a7a7a7" />
131
 
</g>
132
 
`)
133
 
}
134
 
 
135
 
func (s *CanvasSuite) TestIconClipPath(c *gc.C) {
136
 
        // Ensure that the icon ClipPath returns the correctly sizes clipping Circle
137
 
        var buf bytes.Buffer
138
 
        svg := svg.New(&buf)
139
 
        canvas := Canvas{}
140
 
        canvas.iconClipPath(svg)
141
 
        c.Assert(buf.String(), gc.Equals,
142
 
                `<circle cx="47" cy="49" r="45" id="application-icon-mask" fill="none" />
143
 
<clipPath id="clip-mask" ><use x="0" y="0" xlink:href="#application-icon-mask" />
144
 
</clipPath>
145
 
`)
146
 
}
147
 
 
148
 
func (s *CanvasSuite) TestLayout(c *gc.C) {
149
 
        // Ensure that the SVG is sized exactly around the positioned applications.
150
 
        canvas := Canvas{}
151
 
        canvas.addApplication(&application{
152
 
                name: "application1",
153
 
                point: image.Point{
154
 
                        X: 0,
155
 
                        Y: 0,
156
 
                },
157
 
        })
158
 
        canvas.addApplication(&application{
159
 
                name: "application2",
160
 
                point: image.Point{
161
 
                        X: 100,
162
 
                        Y: 100,
163
 
                },
164
 
        })
165
 
        width, height := canvas.layout()
166
 
        c.Assert(width, gc.Equals, 281)
167
 
        c.Assert(height, gc.Equals, 281)
168
 
        canvas.addApplication(&application{
169
 
                name: "application3",
170
 
                point: image.Point{
171
 
                        X: -100,
172
 
                        Y: -100,
173
 
                },
174
 
        })
175
 
        canvas.addApplication(&application{
176
 
                name: "application4",
177
 
                point: image.Point{
178
 
                        X: -100,
179
 
                        Y: 100,
180
 
                },
181
 
        })
182
 
        canvas.addApplication(&application{
183
 
                name: "application5",
184
 
                point: image.Point{
185
 
                        X: 200,
186
 
                        Y: -100,
187
 
                },
188
 
        })
189
 
        width, height = canvas.layout()
190
 
        c.Assert(width, gc.Equals, 481)
191
 
        c.Assert(height, gc.Equals, 381)
192
 
}
193
 
 
194
 
func (s *CanvasSuite) TestMarshal(c *gc.C) {
195
 
        // Ensure that the internal representation of the canvas can be marshalled
196
 
        // to SVG.
197
 
        var buf bytes.Buffer
198
 
        canvas := Canvas{}
199
 
        applicationA := &application{
200
 
                name:      "application-a",
201
 
                charmPath: "trusty/svc-a",
202
 
                point: image.Point{
203
 
                        X: 0,
204
 
                        Y: 0,
205
 
                },
206
 
                iconSrc: []byte(`
207
 
                        <svg xmlns="http://www.w3.org/2000/svg" class="blah">
208
 
                                <circle cx="20" cy="20" r="20" style="fill:#000" />
209
 
                        </svg>`),
210
 
        }
211
 
        applicationB := &application{
212
 
                name: "application-b",
213
 
                point: image.Point{
214
 
                        X: 100,
215
 
                        Y: 100,
216
 
                },
217
 
        }
218
 
        canvas.addApplication(applicationA)
219
 
        canvas.addApplication(applicationB)
220
 
        canvas.addRelation(&applicationRelation{
221
 
                name:         "relation",
222
 
                applicationA: applicationA,
223
 
                applicationB: applicationB,
224
 
        })
225
 
        canvas.Marshal(&buf)
226
 
        c.Logf("%s", buf.Bytes())
227
 
        assertXMLEqual(c, buf.Bytes(), []byte(`
228
 
<?xml version="1.0"?>
229
 
<!-- Generated by SVGo -->
230
 
<svg width="281" height="281"
231
 
     style="font-family:Ubuntu, sans-serif;" viewBox="0 0 281 281"
232
 
     xmlns="http://www.w3.org/2000/svg"
233
 
     xmlns:xlink="http://www.w3.org/1999/xlink">
234
 
<defs>
235
 
<g id="healthCircle" transform="scale(1.1)" >`+assets.RelationIconHealthy+`
236
 
</g>
237
 
<svg xmlns="http://www.w3.org/2000/svg" class="blah" id="icon-1">
238
 
&#x9;&#x9;&#x9;&#x9;<circle cx="20" cy="20" r="20" style="fill:#000"></circle>
239
 
&#x9;&#x9;&#x9;</svg></defs>
240
 
<circle cx="47" cy="49" r="45" id="application-icon-mask" fill="none" />
241
 
<clipPath id="clip-mask" ><use x="0" y="0" xlink:href="#application-icon-mask" />
242
 
</clipPath>
243
 
<g id="relations">
244
 
<g >
245
 
<title>relation</title>
246
 
<line x1="90" y1="90" x2="190" y2="190" stroke="#a7a7a7" stroke-width="1px" stroke-dasharray="62.71, 16" />
247
 
<use x="132" y="132" xlink:href="#healthCircle" />
248
 
<circle cx="153" cy="153" r="4" fill="#a7a7a7" />
249
 
<circle cx="126" cy="126" r="4" fill="#a7a7a7" />
250
 
</g>
251
 
</g>
252
 
<g id="applications">
253
 
<g transform="translate(0,0)" >
254
 
<title>application-a</title>
255
 
<circle cx="90" cy="90" r="90" class="application-block" fill="#f5f5f5" stroke="#888" stroke-width="1" />
256
 
<use x="0" y="0" xlink:href="#icon-1" transform="translate(42,42)" width="96" height="96" clip-path="url(#clip-mask)" />
257
 
<rect x="0" y="135" width="180" height="32" rx="2" ry="2" fill="rgba(220, 220, 220, 0.8)" />
258
 
<text x="90" y="157" text-anchor="middle" style="font-weight:200" >application-a</text>
259
 
</g>
260
 
<g transform="translate(100,100)" >
261
 
<title>application-b</title>
262
 
<circle cx="90" cy="90" r="90" class="application-block" fill="#f5f5f5" stroke="#888" stroke-width="1" />
263
 
<image x="42" y="42" width="96" height="96" xlink:href="" clip-path="url(#clip-mask)" />
264
 
<rect x="0" y="135" width="180" height="32" rx="2" ry="2" fill="rgba(220, 220, 220, 0.8)" />
265
 
<text x="90" y="157" text-anchor="middle" style="font-weight:200" >application-b</text>
266
 
</g>
267
 
</g>
268
 
</svg>
269
 
`))
270
 
}
271
 
 
272
 
func assertXMLEqual(c *gc.C, obtained, expected []byte) {
273
 
        toksObtained := xmlTokens(c, obtained)
274
 
        toksExpected := xmlTokens(c, expected)
275
 
        c.Assert(toksObtained, jc.DeepEquals, toksExpected)
276
 
}
277
 
 
278
 
func xmlTokens(c *gc.C, data []byte) []xml.Token {
279
 
        dec := xml.NewDecoder(bytes.NewReader(data))
280
 
        var toks []xml.Token
281
 
        for {
282
 
                tok, err := dec.Token()
283
 
                if err == io.EOF {
284
 
                        return toks
285
 
                }
286
 
                c.Assert(err, gc.IsNil)
287
 
 
288
 
                if cdata, ok := tok.(xml.CharData); ok {
289
 
                        // It's char data - trim all white space and ignore it
290
 
                        // if it's all blank.
291
 
                        cdata = bytes.TrimSpace(cdata)
292
 
                        if len(cdata) == 0 {
293
 
                                continue
294
 
                        }
295
 
                        tok = cdata
296
 
                }
297
 
                toks = append(toks, xml.CopyToken(tok))
298
 
        }
299
 
}