@cryptotaxi247 / kubo / commits / 452a1d28a

test: refactor some utities out of mod package

License: MIT Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>

Jakub Sztandera committed Aug 18, 2016 at 22:34 UTC 452a1d28a31142166beac73f5f4f7d69f7fe3a49
3 files changed +154 -184
unixfs/io/dagserv_test.go
+5 -51
@@ -1,63 +1,17 @@
1 package io
2
3 import (
4 - "bytes"
5 - "fmt"
6 - "io"
4 "io/ioutil"
5 "testing"
6
10 - imp "github.com/ipfs/go-ipfs/importer"
11 - "github.com/ipfs/go-ipfs/importer/chunk"
12 - mdag "github.com/ipfs/go-ipfs/merkledag"
13 - mdagmock "github.com/ipfs/go-ipfs/merkledag/test"
14 -
15 - u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
7 context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
17 -)
18 -
19 -func sizeSplitterGen(size int64) chunk.SplitterGen {
20 - return func(r io.Reader) chunk.Splitter {
21 - return chunk.NewSizeSplitter(r, size)
22 - }
23 -}
24 -
25 -func getNode(t testing.TB, dserv mdag.DAGService, data []byte) *mdag.Node {
26 - in := bytes.NewReader(data)
27 - node, err := imp.BuildTrickleDagFromReader(dserv, sizeSplitterGen(500)(in))
28 - if err != nil {
29 - t.Fatal(err)
30 - }
31 -
32 - return node
33 -}
8
35 -func getRandomNode(t testing.TB, dserv mdag.DAGService, size int64) ([]byte, *mdag.Node) {
36 - in := io.LimitReader(u.NewTimeSeededRand(), size)
37 - buf, err := ioutil.ReadAll(in)
38 - if err != nil {
39 - t.Fatal(err)
40 - }
41 -
42 - node := getNode(t, dserv, buf)
43 - return buf, node
44 -}
45 -
46 -func arrComp(a, b []byte) error {
47 - if len(a) != len(b) {
48 - return fmt.Errorf("Arrays differ in length. %d != %d", len(a), len(b))
49 - }
50 - for i, v := range a {
51 - if v != b[i] {
52 - return fmt.Errorf("Arrays differ at index: %d", i)
53 - }
54 - }
55 - return nil
56 -}
9 + testu "github.com/ipfs/go-ipfs/unixfs/test"
10 +)
11
12 func TestBasicRead(t *testing.T) {
59 - dserv := mdagmock.Mock()
60 - inbuf, node := getRandomNode(t, dserv, 1024)
13 + dserv := testu.GetDAGServ()
14 + inbuf, node := testu.GetRandomNode(t, dserv, 1024)
15 ctx, closer := context.WithCancel(context.Background())
16 defer closer()
17
@@ -71,7 +25,7 @@ func TestBasicRead(t *testing.T) {
25 t.Fatal(err)
26 }
27
74 - err = arrComp(inbuf, outbuf)
28 + err = testu.ArrComp(inbuf, outbuf)
29 if err != nil {
30 t.Fatal(err)
31 }
unixfs/mod/dagmodifier_test.go
+56 -133
@@ -2,7 +2,6 @@ package mod
2
3 import (
4 "fmt"
5 - "io"
5 "io/ioutil"
6 "os"
7 "testing"
@@ -10,13 +9,12 @@ import (
9 "github.com/ipfs/go-ipfs/blocks/blockstore"
10 bs "github.com/ipfs/go-ipfs/blockservice"
11 "github.com/ipfs/go-ipfs/exchange/offline"
13 - imp "github.com/ipfs/go-ipfs/importer"
14 - "github.com/ipfs/go-ipfs/importer/chunk"
12 h "github.com/ipfs/go-ipfs/importer/helpers"
13 trickle "github.com/ipfs/go-ipfs/importer/trickle"
14 mdag "github.com/ipfs/go-ipfs/merkledag"
15 ft "github.com/ipfs/go-ipfs/unixfs"
16 uio "github.com/ipfs/go-ipfs/unixfs/io"
17 + testu "github.com/ipfs/go-ipfs/unixfs/test"
18
19 u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
20 context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
@@ -24,14 +22,6 @@ import (
22 "gx/ipfs/QmbzuUusHqaLLoNTDEVLcSF6vZDHZDLPC7p4bztRvvkXxU/go-datastore/sync"
23 )
24
27 -func getMockDagServ(t testing.TB) mdag.DAGService {
28 - dstore := ds.NewMapDatastore()
29 - tsds := sync.MutexWrap(dstore)
30 - bstore := blockstore.NewBlockstore(tsds)
31 - bserv := bs.New(bstore, offline.Exchange(bstore))
32 - return mdag.NewDAGService(bserv)
33 -}
34 -
25 func getMockDagServAndBstore(t testing.TB) (mdag.DAGService, blockstore.GCBlockstore) {
26 dstore := ds.NewMapDatastore()
27 tsds := sync.MutexWrap(dstore)
@@ -41,26 +31,6 @@ func getMockDagServAndBstore(t testing.TB) (mdag.DAGService, blockstore.GCBlocks
31 return dserv, bstore
32 }
33
44 -func getNode(t testing.TB, dserv mdag.DAGService, size int64) ([]byte, *mdag.Node) {
45 - in := io.LimitReader(u.NewTimeSeededRand(), size)
46 - node, err := imp.BuildTrickleDagFromReader(dserv, sizeSplitterGen(500)(in))
47 - if err != nil {
48 - t.Fatal(err)
49 - }
50 -
51 - dr, err := uio.NewDagReader(context.Background(), node, dserv)
52 - if err != nil {
53 - t.Fatal(err)
54 - }
55 -
56 - b, err := ioutil.ReadAll(dr)
57 - if err != nil {
58 - t.Fatal(err)
59 - }
60 -
61 - return b, node
62 -}
63 -
34 func testModWrite(t *testing.T, beg, size uint64, orig []byte, dm *DagModifier) []byte {
35 newdata := make([]byte, size)
36 r := u.NewTimeSeededRand()
@@ -100,26 +70,20 @@ func testModWrite(t *testing.T, beg, size uint64, orig []byte, dm *DagModifier)
70 t.Fatal(err)
71 }
72
103 - err = arrComp(after, orig)
73 + err = testu.ArrComp(after, orig)
74 if err != nil {
75 t.Fatal(err)
76 }
77 return orig
78 }
79
110 -func sizeSplitterGen(size int64) chunk.SplitterGen {
111 - return func(r io.Reader) chunk.Splitter {
112 - return chunk.NewSizeSplitter(r, size)
113 - }
114 -}
115 -
80 func TestDagModifierBasic(t *testing.T) {
117 - dserv := getMockDagServ(t)
118 - b, n := getNode(t, dserv, 50000)
81 + dserv := testu.GetDAGServ()
82 + b, n := testu.GetRandomNode(t, dserv, 50000)
83 ctx, cancel := context.WithCancel(context.Background())
84 defer cancel()
85
122 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
86 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
87 if err != nil {
88 t.Fatal(err)
89 }
@@ -168,13 +132,13 @@ func TestDagModifierBasic(t *testing.T) {
132 }
133
134 func TestMultiWrite(t *testing.T) {
171 - dserv := getMockDagServ(t)
172 - _, n := getNode(t, dserv, 0)
135 + dserv := testu.GetDAGServ()
136 + n := testu.GetEmptyNode(t, dserv)
137
138 ctx, cancel := context.WithCancel(context.Background())
139 defer cancel()
140
177 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
141 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
142 if err != nil {
143 t.Fatal(err)
144 }
@@ -214,20 +178,20 @@ func TestMultiWrite(t *testing.T) {
178 t.Fatal(err)
179 }
180
217 - err = arrComp(rbuf, data)
181 + err = testu.ArrComp(rbuf, data)
182 if err != nil {
183 t.Fatal(err)
184 }
185 }
186
187 func TestMultiWriteAndFlush(t *testing.T) {
224 - dserv := getMockDagServ(t)
225 - _, n := getNode(t, dserv, 0)
188 + dserv := testu.GetDAGServ()
189 + n := testu.GetEmptyNode(t, dserv)
190
191 ctx, cancel := context.WithCancel(context.Background())
192 defer cancel()
193
230 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
194 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
195 if err != nil {
196 t.Fatal(err)
197 }
@@ -262,20 +226,20 @@ func TestMultiWriteAndFlush(t *testing.T) {
226 t.Fatal(err)
227 }
228
265 - err = arrComp(rbuf, data)
229 + err = testu.ArrComp(rbuf, data)
230 if err != nil {
231 t.Fatal(err)
232 }
233 }
234
235 func TestWriteNewFile(t *testing.T) {
272 - dserv := getMockDagServ(t)
273 - _, n := getNode(t, dserv, 0)
236 + dserv := testu.GetDAGServ()
237 + n := testu.GetEmptyNode(t, dserv)
238
239 ctx, cancel := context.WithCancel(context.Background())
240 defer cancel()
241
278 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
242 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
243 if err != nil {
244 t.Fatal(err)
245 }
@@ -306,19 +270,19 @@ func TestWriteNewFile(t *testing.T) {
270 t.Fatal(err)
271 }
272
309 - if err := arrComp(data, towrite); err != nil {
273 + if err := testu.ArrComp(data, towrite); err != nil {
274 t.Fatal(err)
275 }
276 }
277
278 func TestMultiWriteCoal(t *testing.T) {
315 - dserv := getMockDagServ(t)
316 - _, n := getNode(t, dserv, 0)
279 + dserv := testu.GetDAGServ()
280 + n := testu.GetEmptyNode(t, dserv)
281
282 ctx, cancel := context.WithCancel(context.Background())
283 defer cancel()
284
321 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
285 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
286 if err != nil {
287 t.Fatal(err)
288 }
@@ -351,20 +315,20 @@ func TestMultiWriteCoal(t *testing.T) {
315 t.Fatal(err)
316 }
317
354 - err = arrComp(rbuf, data)
318 + err = testu.ArrComp(rbuf, data)
319 if err != nil {
320 t.Fatal(err)
321 }
322 }
323
324 func TestLargeWriteChunks(t *testing.T) {
361 - dserv := getMockDagServ(t)
362 - _, n := getNode(t, dserv, 0)
325 + dserv := testu.GetDAGServ()
326 + n := testu.GetEmptyNode(t, dserv)
327
328 ctx, cancel := context.WithCancel(context.Background())
329 defer cancel()
330
367 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
331 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
332 if err != nil {
333 t.Fatal(err)
334 }
@@ -390,19 +354,19 @@ func TestLargeWriteChunks(t *testing.T) {
354 t.Fatal(err)
355 }
356
393 - if err = arrComp(out, data); err != nil {
357 + if err = testu.ArrComp(out, data); err != nil {
358 t.Fatal(err)
359 }
360
361 }
362
363 func TestDagTruncate(t *testing.T) {
400 - dserv := getMockDagServ(t)
401 - b, n := getNode(t, dserv, 50000)
364 + dserv := testu.GetDAGServ()
365 + b, n := testu.GetRandomNode(t, dserv, 50000)
366 ctx, cancel := context.WithCancel(context.Background())
367 defer cancel()
368
405 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
369 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
370 if err != nil {
371 t.Fatal(err)
372 }
@@ -430,7 +394,7 @@ func TestDagTruncate(t *testing.T) {
394 t.Fatal(err)
395 }
396
433 - if err = arrComp(out, b[:12345]); err != nil {
397 + if err = testu.ArrComp(out, b[:12345]); err != nil {
398 t.Fatal(err)
399 }
400
@@ -464,12 +428,12 @@ func TestDagTruncate(t *testing.T) {
428 }
429
430 func TestSparseWrite(t *testing.T) {
467 - dserv := getMockDagServ(t)
468 - _, n := getNode(t, dserv, 0)
431 + dserv := testu.GetDAGServ()
432 + n := testu.GetEmptyNode(t, dserv)
433 ctx, cancel := context.WithCancel(context.Background())
434 defer cancel()
435
472 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
436 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
437 if err != nil {
438 t.Fatal(err)
439 }
@@ -496,18 +460,18 @@ func TestSparseWrite(t *testing.T) {
460 t.Fatal(err)
461 }
462
499 - if err = arrComp(out, buf); err != nil {
463 + if err = testu.ArrComp(out, buf); err != nil {
464 t.Fatal(err)
465 }
466 }
467
468 func TestSeekPastEndWrite(t *testing.T) {
505 - dserv := getMockDagServ(t)
506 - _, n := getNode(t, dserv, 0)
469 + dserv := testu.GetDAGServ()
470 + n := testu.GetEmptyNode(t, dserv)
471 ctx, cancel := context.WithCancel(context.Background())
472 defer cancel()
473
510 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
474 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
475 if err != nil {
476 t.Fatal(err)
477 }
@@ -543,18 +507,18 @@ func TestSeekPastEndWrite(t *testing.T) {
507 t.Fatal(err)
508 }
509
546 - if err = arrComp(out, buf); err != nil {
510 + if err = testu.ArrComp(out, buf); err != nil {
511 t.Fatal(err)
512 }
513 }
514
515 func TestRelativeSeek(t *testing.T) {
552 - dserv := getMockDagServ(t)
553 - _, n := getNode(t, dserv, 0)
516 + dserv := testu.GetDAGServ()
517 + n := testu.GetEmptyNode(t, dserv)
518 ctx, cancel := context.WithCancel(context.Background())
519 defer cancel()
520
557 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
521 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
522 if err != nil {
523 t.Fatal(err)
524 }
@@ -579,13 +543,12 @@ func TestRelativeSeek(t *testing.T) {
543 }
544
545 func TestInvalidSeek(t *testing.T) {
582 - dserv := getMockDagServ(t)
583 -
584 - _, n := getNode(t, dserv, 0)
546 + dserv := testu.GetDAGServ()
547 + n := testu.GetEmptyNode(t, dserv)
548 ctx, cancel := context.WithCancel(context.Background())
549 defer cancel()
550
588 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
551 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
552 if err != nil {
553 t.Fatal(err)
554 }
@@ -597,13 +560,13 @@ func TestInvalidSeek(t *testing.T) {
560 }
561
562 func TestEndSeek(t *testing.T) {
600 - dserv := getMockDagServ(t)
563 + dserv := testu.GetDAGServ()
564
602 - _, n := getNode(t, dserv, 0)
565 + n := testu.GetEmptyNode(t, dserv)
566 ctx, cancel := context.WithCancel(context.Background())
567 defer cancel()
568
606 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
569 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
570 if err != nil {
571 t.Fatal(err)
572 }
@@ -630,13 +593,13 @@ func TestEndSeek(t *testing.T) {
593 }
594
595 func TestReadAndSeek(t *testing.T) {
633 - dserv := getMockDagServ(t)
596 + dserv := testu.GetDAGServ()
597
635 - _, n := getNode(t, dserv, 0)
598 + n := testu.GetEmptyNode(t, dserv)
599 ctx, cancel := context.WithCancel(context.Background())
600 defer cancel()
601
639 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
602 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
603 if err != nil {
604 t.Fatal(err)
605 }
@@ -698,13 +661,13 @@ func TestReadAndSeek(t *testing.T) {
661 }
662
663 func TestCtxRead(t *testing.T) {
701 - dserv := getMockDagServ(t)
664 + dserv := testu.GetDAGServ()
665
703 - _, n := getNode(t, dserv, 0)
666 + n := testu.GetEmptyNode(t, dserv)
667 ctx, cancel := context.WithCancel(context.Background())
668 defer cancel()
669
707 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
670 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
671 if err != nil {
672 t.Fatal(err)
673 }
@@ -720,7 +683,7 @@ func TestCtxRead(t *testing.T) {
683 if err != nil {
684 t.Fatal(err)
685 }
723 - err = arrComp(readBuf, []byte{0, 1, 2, 3})
686 + err = testu.ArrComp(readBuf, []byte{0, 1, 2, 3})
687 if err != nil {
688 t.Fatal(err)
689 }
@@ -730,14 +693,14 @@ func TestCtxRead(t *testing.T) {
693
694 func BenchmarkDagmodWrite(b *testing.B) {
695 b.StopTimer()
733 - dserv := getMockDagServ(b)
734 - _, n := getNode(b, dserv, 0)
696 + dserv := testu.GetDAGServ()
697 + n := testu.GetEmptyNode(b, dserv)
698 ctx, cancel := context.WithCancel(context.Background())
699 defer cancel()
700
701 wrsize := 4096
702
740 - dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
703 + dagmod, err := NewDagModifier(ctx, n, dserv, testu.SizeSplitterGen(512))
704 if err != nil {
705 b.Fatal(err)
706 }
@@ -756,43 +719,3 @@ func BenchmarkDagmodWrite(b *testing.B) {
719 }
720 }
721 }
759 -
760 -func arrComp(a, b []byte) error {
761 - if len(a) != len(b) {
762 - return fmt.Errorf("Arrays differ in length. %d != %d", len(a), len(b))
763 - }
764 - for i, v := range a {
765 - if v != b[i] {
766 - return fmt.Errorf("Arrays differ at index: %d", i)
767 - }
768 - }
769 - return nil
770 -}
771 -
772 -func printDag(nd *mdag.Node, ds mdag.DAGService, indent int) {
773 - pbd, err := ft.FromBytes(nd.Data())
774 - if err != nil {
775 - panic(err)
776 - }
777 -
778 - for i := 0; i < indent; i++ {
779 - fmt.Print(" ")
780 - }
781 - fmt.Printf("{size = %d, type = %s, children = %d", pbd.GetFilesize(), pbd.GetType().String(), len(pbd.GetBlocksizes()))
782 - if len(nd.Links) > 0 {
783 - fmt.Println()
784 - }
785 - for _, lnk := range nd.Links {
786 - child, err := lnk.GetNode(context.Background(), ds)
787 - if err != nil {
788 - panic(err)
789 - }
790 - printDag(child, ds, indent+1)
791 - }
792 - if len(nd.Links) > 0 {
793 - for i := 0; i < indent; i++ {
794 - fmt.Print(" ")
795 - }
796 - }
797 - fmt.Println("}")
798 -}
unixfs/test/utils.go new
+93
@@ -0,0 +1,93 @@
1 +package testu
2 +
3 +import (
4 + "bytes"
5 + "fmt"
6 + "io"
7 + "io/ioutil"
8 + "testing"
9 +
10 + imp "github.com/ipfs/go-ipfs/importer"
11 + "github.com/ipfs/go-ipfs/importer/chunk"
12 + mdag "github.com/ipfs/go-ipfs/merkledag"
13 + mdagmock "github.com/ipfs/go-ipfs/merkledag/test"
14 + ft "github.com/ipfs/go-ipfs/unixfs"
15 +
16 + u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
17 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
18 +)
19 +
20 +func SizeSplitterGen(size int64) chunk.SplitterGen {
21 + return func(r io.Reader) chunk.Splitter {
22 + return chunk.NewSizeSplitter(r, size)
23 + }
24 +}
25 +
26 +func GetDAGServ() mdag.DAGService {
27 + return mdagmock.Mock()
28 +}
29 +
30 +func GetNode(t testing.TB, dserv mdag.DAGService, data []byte) *mdag.Node {
31 + in := bytes.NewReader(data)
32 + node, err := imp.BuildTrickleDagFromReader(dserv, SizeSplitterGen(500)(in))
33 + if err != nil {
34 + t.Fatal(err)
35 + }
36 +
37 + return node
38 +}
39 +
40 +func GetEmptyNode(t testing.TB, dserv mdag.DAGService) *mdag.Node {
41 + return GetNode(t, dserv, []byte{})
42 +}
43 +
44 +func GetRandomNode(t testing.TB, dserv mdag.DAGService, size int64) ([]byte, *mdag.Node) {
45 + in := io.LimitReader(u.NewTimeSeededRand(), size)
46 + buf, err := ioutil.ReadAll(in)
47 + if err != nil {
48 + t.Fatal(err)
49 + }
50 +
51 + node := GetNode(t, dserv, buf)
52 + return buf, node
53 +}
54 +
55 +func ArrComp(a, b []byte) error {
56 + if len(a) != len(b) {
57 + return fmt.Errorf("Arrays differ in length. %d != %d", len(a), len(b))
58 + }
59 + for i, v := range a {
60 + if v != b[i] {
61 + return fmt.Errorf("Arrays differ at index: %d", i)
62 + }
63 + }
64 + return nil
65 +}
66 +
67 +func PrintDag(nd *mdag.Node, ds mdag.DAGService, indent int) {
68 + pbd, err := ft.FromBytes(nd.Data())
69 + if err != nil {
70 + panic(err)
71 + }
72 +
73 + for i := 0; i < indent; i++ {
74 + fmt.Print(" ")
75 + }
76 + fmt.Printf("{size = %d, type = %s, children = %d", pbd.GetFilesize(), pbd.GetType().String(), len(pbd.GetBlocksizes()))
77 + if len(nd.Links) > 0 {
78 + fmt.Println()
79 + }
80 + for _, lnk := range nd.Links {
81 + child, err := lnk.GetNode(context.Background(), ds)
82 + if err != nil {
83 + panic(err)
84 + }
85 + PrintDag(child, ds, indent+1)
86 + }
87 + if len(nd.Links) > 0 {
88 + for i := 0; i < indent; i++ {
89 + fmt.Print(" ")
90 + }
91 + }
92 + fmt.Println("}")
93 +}