Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(508)

Side by Side Diff: go/src/infra/libs/git/tree_test.go

Issue 662113003: Drover's back, baby! (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git/+/master
Patch Set: more tests and refactors Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « go/src/infra/libs/git/treeDiff.go ('k') | go/src/infra/libs/git/types.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package git
6
7 import (
8 "fmt"
9 "strings"
10 "testing"
11
12 . "github.com/smartystreets/goconvey/convey"
13
14 "infra/libs/infra_util"
15 )
16
17 type FakeGitEntry struct {
18 data string
19 typ ObjectType
20 size int
21 }
22
23 type FakeGitService map[ObjectID]FakeGitEntry
24
25 func (f FakeGitService) GetObjectID(id Identifiable) (InternableObject, error) {
26 if id.ID().RawString() == "TestsFailureObjectID" {
27 return &Blob{}, fmt.Errorf("Cannot get TestsFailureObjectID")
28 }
29 obj, ok := f[*id.ID()]
30 if !ok {
31 return nil, nil
32 }
33 return ObjectFromRawWithID(id, obj.typ, []byte(obj.data))
34 }
35
36 func (f FakeGitService) HasObjectID(id Identifiable) bool {
37 o, _ := f.GetObjectID(id)
38 return o != nil
39 }
40
41 func (f FakeGitService) ObjectInfo(objectish string) *ObjectInfo {
42 // technically this needs to implement all of rev-parse, but we'll just
43 // cheat for the bits we need right now (e.g. <hash>:)
44 id, err := MakeObjectIDErr(objectish[:len(objectish)-1])
45 if err != nil {
46 Println("FakeGitService cannot process", objectish)
47 return nil
48 }
49 if objectish[len(objectish)-1] == ':' {
50 o, err := f.GetObjectID(id)
51 if err != nil {
52 return nil
53 }
54 if commit, ok := o.(*Commit); !ok {
55 Println("Has is not a commit", objectish)
56 return nil
57 } else {
58 return f.ObjectInfoID(commit.Tree())
59 }
60 } else {
61 Println("FakeGitService cannot process", objectish)
62 return nil
63 }
64 }
65
66 func (f FakeGitService) ObjectInfoID(id Identifiable) *ObjectInfo {
67 obj, ok := f[*id.ID()]
68 if !ok {
69 return nil
70 }
71 return &ObjectInfo{obj.typ, obj.size, id.ID()}
72 }
73
74 func (f FakeGitService) Intern(o InternableObject) (*ObjectID, error) {
75 return InternImpl(f, o, func(data string) (string, error) {
76 f[*o.ID()] = FakeGitEntry{data, o.Type(), len(data)}
77 return o.ID().String(), nil
78 })
79 }
80
81 func TestTree(t *testing.T) {
82 t.Parallel()
83
84 Convey("Tree", t, func() {
85
86 Convey("Constructors", func() {
87
88 Convey("Text", func() {
89
90 Convey("Should parse", func() {
91 txt := strings.Join([]string{
92 "100644 blob 302296b172eb2152d24 9734ed93690c7213f0ea0\t.gitignore",
93 "100644 blob d0225511d9de0193a95 f81900c70cbc50b759818\t.gitmodules",
94 "100644 blob dcd5f302bb21c46488d 813a57a543f6afa94b8b4\t.netrwhist",
95 "040000 tree c7dcb4bbcdaf65ea75e a7735c7694d412f66ddb6\tAudio",
96 "160000 commit 3bb7c33fbb5721e2b e5ff963f8f3ba78e4878983\tLS_COLORS",
97 "100644 blob 1402d9c72db11e48bb1 5a5c4163e5fbbbd1a6218\tREADME.md",
98 "040000 tree 3bfce6fec987eb7a424 34e15a7033c7818c684fe\tUltiSnips",
99 }, "\n")
100
101 tree, err := NewTreeFromText([]byte(txt) )
102 So(err, ShouldBeNil)
103 So(tree.Type(), ShouldEqual, TreeType)
104 So(tree.NumChildren(), ShouldEqual, 7)
105
106 So(tree.Complete(), ShouldBeTrue)
107 So(tree.ID().String(), ShouldEqual, "279 32b52d6c0f6381fbfe8505d08ee45c33b7b88")
108 })
109
110 Convey("Should parse with quoted paths", func() {
111 txt := "100644 blob 302296b172eb2152d249 734ed93690c7213f0ea0\t\"foo\\nbar\"\n"
112
113 tree, err := NewTreeFromText([]byte(txt) )
114 So(err, ShouldBeNil)
115 So(tree.NumChildren(), ShouldEqual, 1)
116
117 c := tree.GetChild("foo\nbar")
118 So(c, ShouldNotBeNil)
119 So(c.Object.Type(), ShouldEqual, BlobTyp e)
120 })
121
122 Convey("Should reject bad text", func() {
123 bads := []string{
124 "",
125 "100644 blob nubsauce\t\"wat\"\n ",
126 "hi blob 302296b172eb2152d249734 ed93690c7213f0ea0\t\"wat\"\n",
127 "100644 blob 302296b172eb2152d24 9734ed93690c7213f0ea0\t\"wat\n",
128 "100644 blob 302296b172eb2152d24 9734ed93690c7213f0ea0 bob\n",
129 "blob 302296b172eb2152d249734ed9 3690c7213f0ea0\tbob\n",
130 "100644 302296b172eb2152d249734e d93690c7213f0ea0\tbob\n",
131 "0 blob 302296b172eb2152d249734e d93690c7213f0ea0\tbob\n",
132 "100644 blob 302296b172eb2152d24 9734ed93690c7213f0ea0\t\n",
133 }
134 for _, txt := range bads {
135 txt := txt
136 Convey(fmt.Sprintf("%#v", txt), func() {
137 _, err := NewTreeFromTex t([]byte(txt))
138 So(err, ShouldNotBeNil)
139 })
140 }
141 })
142
143 Convey("Should reject nil", func() {
144 _, err := NewTreeFromText(nil)
145 So(err, ShouldNotBeNil)
146 })
147 })
148
149 Convey("Binary", func() {
150
151 Convey("Should parse", func() {
152 bin := strings.Join([]string{
153 "100644 .gitignore\x000\"\x96\xb 1r\xeb!R\xd2IsN\xd96\x90\xc7!?\x0e\xa0",
154 "100644 .gitmodules\x00\xd0\"U\x 11\xd9\xde\x01\x93\xa9_\x81\x90\x0cp\xcb\xc5\x0bu\x98\x18",
155 "100644 .netrwhist\x00\xa3\xea\x dd\x97*\x16\x08\x88\x11\x17\xee7I\x8a\t\xb1\xbd\x82et",
156 "40000 Audio\x00\xc7\xdc\xb4\xbb \xcd\xafe\xeau\xeaw5\xc7iMA/f\xdd\xb6",
157 "160000 LS_COLORS\x00;\xb7\xc3?\ xbbW!\xe2\xbe_\xf9c\xf8\xf3\xbax\xe4\x87\x89\x83",
158 "100644 README.md\x00\x14\x02\xd 9\xc7-\xb1\x1eH\xbb\x15\xa5\xc4\x16>_\xbb\xbd\x1ab\x18",
159 "40000 UltiSnips\x00;\xfc\xe6\xf e\xc9\x87\xebzBCN\x15\xa7\x03<x\x18\xc6\x84\xfe",
160 }, "")
161
162 tree, err := NewTreeFromRaw([]byte(bin))
163 So(err, ShouldBeNil)
164 So(tree.NumChildren(), ShouldEqual, 7)
165 So(tree.ID().String(), ShouldEqual, "c86 f07a67fcfadb63a9686a4bb1851cc4b01d7bc")
166
167 Convey("Round-trip", func() {
168 So(tree.RawString(), ShouldEqual , bin)
169 })
170 })
171
172 Convey("Empty should parse", func() {
173 tree, err := NewTreeFromRaw(nil)
174 So(err, ShouldBeNil)
175 So(tree.NumChildren(), ShouldEqual, 0)
176 So(tree.ID().String(), ShouldEqual, Empt yTreeHash)
177
178 Convey("Round-trip", func() {
179 So(tree.RawString(), ShouldEqual , "")
180 })
181
182 Convey("Matches NewEmptyTree", func() {
183 empty := NewEmptyTree(&NoID, 0)
184 empty.RawString() // re-calculat e the empty hash
185 So(empty.ID(), ShouldResemble, t ree.ID())
186 })
187 })
188
189 Convey("Should reject bad binaries", func() {
190 bads := []string{
191 "hi .gitignore\x000\"\x96\xb1r\x eb!R\xd2IsN\xd96\x90\xc7!?\x0e\xa0",
192 "0 .gitignore\x000\"\x96\xb1r\xe b!R\xd2IsN\xd96\x90\xc7!?\x0e\xa0",
193 "100644\x000\"\x96\xb1r\xeb!R\xd 2IsN\xd96\x90\xc7!?\x0e\xa0",
194 "100644 bob\x000\"\x96\xb1\xeb!R \xd2IsN\xd96\x90\xc7!?\x0e\xa0",
195 }
196 for _, bin := range bads {
197 bin := bin
198 Convey(fmt.Sprintf("%#v", bin), func() {
199 _, err := NewTreeFromRaw ([]byte(bin))
200 So(err, ShouldNotBeNil)
201 })
202 }
203 })
204 })
205 })
206
207 Convey("TreeManipulation", func() {
208 tree := NewEmptyTree(&NoID, 0)
209
210 Convey("GetChild", func() {
211 names := []string{
212 "",
213 "bob",
214 "bob\nnewline",
215 "bob/subitem",
216 }
217 for _, name := range names {
218 name := name
219 Convey(fmt.Sprintf("Returns nil with no children: %#v", name), func() {
220 So(tree.GetChild(name), ShouldBe Nil)
221 })
222 }
223 })
224
225 Convey("SetChild", func() {
226 Convey("cannot set a child on the empty path", f unc() {
227 So(func() { tree.SetChild("", BlankTreeC hild(0)) }, ShouldPanic)
228 })
229
230 Convey("can create intermediate trees for a chil d", func() {
231 c, err := NewEmptyChild(0100644, &NoID)
232 So(err, ShouldBeNil)
233 So(c.Object.Type(), ShouldEqual, BlobTyp e)
234 tree.SetChild("rootblob", c)
235 tree.SetChild("bob/blob", c)
236
237 c, err = NewEmptyChild(040000, MakeObjec tID(EmptyTreeHash))
238 So(err, ShouldBeNil)
239 tree.SetChild("bob/blank_subtree", c)
240
241 c, err = NewEmptyChild(040000, MakeObjec tID("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"))
242 So(err, ShouldBeNil)
243 tree.SetChild("bob/nonblank_subtree", c)
244
245 Convey("the tree was set up correctly", func() {
246 So(tree.NumChildren(), ShouldEqu al, 2)
247 for k := range tree.children {
248 So(k, ShouldBeIn, []stri ng{"bob", "rootblob"})
249 }
250
251 So(tree.GetChild("bob").Object.( *Tree).NumChildren(), ShouldEqual, 3)
252 for k := range tree.GetChild("bo b").Object.(*Tree).children {
253 So(k, ShouldBeIn, []stri ng{"blank_subtree", "blob", "nonblank_subtree"})
254 }
255 })
256
257 Convey("but will panic if you try to cre ate a child of a non-tree", func() {
258 So(func() { tree.SetChild("bob/b lob/fail", BlankTreeChild(0)) }, ShouldPanic)
259 })
260
261 Convey("getting the child of a non-tree is also a panic", func() {
262 So(func() { tree.GetChild("bob/b lob/fail") }, ShouldPanic)
263 })
264
265 Convey("setting a child of a placeholder tree will panic", func() {
266 So(func() { tree.SetChild("bob/n onblank_subtree/happy_days", BlankTreeChild(0)) }, ShouldPanic)
267 })
268
269 Convey("however, setting a child of an e mpty placeholder tree will cause it to exist", func() {
270 c, err := NewEmptyChild(0100644, &NoID)
271 So(err, ShouldBeNil)
272 tree.SetChild("bob/blank_subtree /happy_days", c)
273 So(tree.GetChild("bob/blank_subt ree").Object, ShouldHaveSameTypeAs, tree)
274 })
275
276 Convey("DelChild", func() {
277 Convey("returns when you delete something that's not there", func() {
278 So(tree.DelChild("nerd") , ShouldBeFalse)
279 So(tree.DelChild("whatno w/sup"), ShouldBeFalse)
280 So(tree.DelChild("bob/no there"), ShouldBeFalse)
281 })
282
283 Convey("but will panic if you tr y to delete a subordinate of a blob", func() {
284 So(func() { tree.DelChil d("rootblob/boom") }, ShouldPanic)
285 })
286
287 Convey("It will also clean out d irectories when they are empty", func() {
288 So(tree.DelChild("bob/bl ank_subtree"), ShouldBeTrue)
289 So(tree.DelChild("bob/no nblank_subtree"), ShouldBeTrue)
290 So(tree.DelChild("bob/bl ob"), ShouldBeTrue)
291 So(tree.NumChildren(), S houldEqual, 1)
292 for k := range tree.chil dren {
293 So(k, ShouldBeIn , []string{"rootblob"})
294 }
295 })
296
297 Convey("It can also remove direc tories with content", func() {
298 So(tree.DelChild("bob"), ShouldBeTrue)
299 So(tree.NumChildren(), S houldEqual, 1)
300 for k := range tree.chil dren {
301 So(k, ShouldBeIn , []string{"rootblob"})
302 }
303 })
304 })
305 })
306
307 Convey("Intern(FakeGitService)", func() {
308 s := make(FakeGitService)
309
310 Convey("In an empty tree", func() {
311 Convey("allowMissing should succ eed", func() {
312 id, err := tree.Intern(s , true)
313 So(err, ShouldBeNil)
314 So(id.String(), ShouldEq ual, EmptyTreeHash)
315 })
316
317 Convey("!allowMissing should suc ceed", func() {
318 id, err := tree.Intern(s , true)
319 So(err, ShouldBeNil)
320 So(id.String(), ShouldEq ual, EmptyTreeHash)
321 })
322 })
323
324 Convey("In a tree with an EmptyObject", func() {
325 c, err := NewEmptyChild(0100644, MakeObjectIDForData(BlobType, []byte("sup")))
326 So(err, ShouldBeNil)
327 tree.SetChild("nest/blob", c)
328
329 Convey("allowMissing should succ eed", func() {
330 id, err := tree.Intern(s , true)
331 So(err, ShouldBeNil)
332 So(id.String(), ShouldEq ual, "730bdd0d9d5cb610df9b00df7a622cee291a5453")
333 So(len(s), ShouldEqual, 2)
334 })
335
336 Convey("!allowMissing should fai l", func() {
337 _, err := tree.Intern(s, false)
338 So(err, ShouldNotBeNil)
339 expect := infra_util.Str ingSetFrom(
340 "ME[\"missing no n-internable object: EmptyObject(0b90e2b8567ab715f87fb49c6a0a08ce6f2eb312, blob) \"]")
341 So(err.(*infra_util.Mult iError).ErrorStrings(), ShouldResemble, expect)
342 So(s, ShouldBeEmpty)
343 })
344 })
345
346 Convey("In a tree with a nested Blob", f unc() {
347 tree.SetChild("nest/blob", &Chil d{NewBlobFromRaw([]byte("sup")), Mode(0100644)})
348
349 Convey("allowMissing should succ eed", func() {
350 id, err := tree.Intern(s , true)
351 So(err, ShouldBeNil)
352 So(id.String(), ShouldEq ual, "730bdd0d9d5cb610df9b00df7a622cee291a5453")
353 So(len(s), ShouldEqual, 3)
354 })
355
356 Convey("!allowMissing should suc ceed", func() {
357 id, err := tree.Intern(s , false)
358 So(err, ShouldBeNil)
359 So(id.String(), ShouldEq ual, "730bdd0d9d5cb610df9b00df7a622cee291a5453")
360 So(len(s), ShouldEqual, 3)
361 })
362 })
363
364 Convey("In a tree with a NoID EmptyObjec t", func() {
365 c, err := NewEmptyChild(0100644, &NoID)
366 So(err, ShouldBeNil)
367 tree.SetChild("nest/blob", c)
368
369 Convey("allowMissing should fail ", func() {
370 _, err := tree.Intern(s, true)
371 So(err, ShouldNotBeNil)
372 expect := infra_util.Str ingSetFrom(
373 "ME[\"object has an ID of <NoID>\"]")
374 So(err.(*infra_util.Mult iError).ErrorStrings(), ShouldResemble, expect)
375 So(s, ShouldBeEmpty)
376 })
377
378 Convey("!allowMissing should fai l", func() {
379 _, err := tree.Intern(s, false)
380 So(err, ShouldNotBeNil)
381 expect := infra_util.Str ingSetFrom(
382 "ME[\"missing no n-internable object: EmptyObject(<NoID>, blob)\"]")
383 So(err.(*infra_util.Mult iError).ErrorStrings(), ShouldResemble, expect)
384 So(s, ShouldBeEmpty)
385 })
386 })
387
388 Convey("In a tree with an empty (but ID' d) subtree", func() {
389 sub_id := "a7d0c997159313b124cf5 daec4715ba59c5993d3"
390 c, err := NewEmptyChild(040000, MakeObjectID(sub_id))
391 So(err, ShouldBeNil)
392 tree.SetChild("nest", c)
393
394 Convey("allowMissing should succ eed", func() {
395 _, err := tree.Intern(s, true)
396 So(err, ShouldBeNil)
397 So(len(s), ShouldEqual, 1)
398
399 Convey("and the subtree should retain its ID", func() {
400 So(tree.GetChild ("nest").Object.ID().String(), ShouldEqual, sub_id)
401 })
402 })
403
404 Convey("!allowMissing should fai l", func() {
405 _, err := tree.Intern(s, false)
406 expect := infra_util.Str ingSetFrom(fmt.Sprintf(
407 "missing non-int ernable object: EmptyObject(%s, tree)", sub_id))
408 So(err, ShouldNotBeNil)
409 So(err.(*infra_util.Mult iError).ErrorStrings(), ShouldResemble, expect)
410 So(s, ShouldBeEmpty)
411 })
412 })
413 })
414 })
415 })
416
417 Convey("LoadFullTree", func() {
418 s := make(FakeGitService)
419
420 LT := func(id Identifiable, withBlobs, missingErr bool) (*Tree, error) {
421 o, err := LoadFullTree(s, id, withBlobs, missing Err)
422 if err != nil {
423 return nil, err
424 }
425 return o.(*Tree), nil
426 }
427
428 Convey("with a fully-populated tree", func() {
429 thash := "9fe3bef872f85138118766d83ce0d528fdb522 ad"
430 tree := NewEmptyTree(&NoID, 3)
431 tree.SetChild("sub/blob", &Child{NewBlobFromRaw( []byte("hi")), 0100755})
432 tree.SetChild("sub/happy", &Child{NewBlobFromRaw ([]byte("happy")), 0100755})
433 tree.SetChild("maybeMissing/blob", &Child{NewBlo bFromRaw([]byte("sup")), 0100644})
434 tree.SetChild("nerd", &Child{NewBlobFromRaw([]by te("hi")), 0100644})
435 id, err := tree.Intern(s, false)
436 So(err, ShouldBeNil)
437 So(id.String(), ShouldEqual, thash)
438
439 Convey("Aborts nicely if GetObjectID fails", fun c() {
440 failID := &ObjectID{}
441 copy(failID.raw[:], "TestsFailureObjectI D")
442 c, err := NewEmptyChild(040000, failID)
443 So(err, ShouldBeNil)
444 tree.SetChild("fail/failington", c)
445 id, err := tree.Intern(s, false)
446 So(err, ShouldBeNil)
447 wat, err := LT(id, true, true)
448 Print(wat)
449 So(err, ShouldNotBeNil)
450 })
451
452 Convey("from a missing tree is an error", func() {
453 _, err := LT(MakeObjectIDForData(TreeTyp e, []byte("bob")), true, true)
454 So(err, ShouldNotBeNil)
455 })
456
457 Convey("from a blob is an error", func() {
458 bID, err := s.Intern(NewBlobFromRaw([]by te("sup")))
459 So(err, ShouldBeNil)
460 _, err = LT(bID, true, true)
461 So(err, ShouldNotBeNil)
462 })
463
464 Convey("from a commit which points to a missing tree is an error", func() {
465 c, err := NewCommitFromRaw([]byte(fmt.Sp rintf(`tree %s
466 author Jane Janerton <bob@chromium.org> 123456789 +0000
467 committer Bob Boberton <bob@chromium.org> 123456789 +0000
468
469 Super cool tree commit`, MakeObjectIDForData(TreeType, []byte("bob")))))
470 So(err, ShouldBeNil)
471 s.Intern(c)
472 _, err = LT(c.ID(), true, true)
473 So(err, ShouldNotBeNil)
474 })
475
476 Convey("noBlobs", func() {
477 Convey("missingErr (success)", func() {
478 loaded, err := LT(id, false, tru e)
479 So(err, ShouldBeNil)
480 Println(loaded.GetChild("nerd"))
481 So(loaded.children, ShouldNotRes emble, tree.children)
482 for k := range loaded.children {
483 So(k, ShouldBeIn, []stri ng{"sub", "maybeMissing", "nerd"})
484 }
485 So(loaded.GetChild("sub").Object .ID(), ShouldResemble,
486 tree.GetChild("sub").Obj ect.ID())
487 So(loaded.GetChild("sub/blob").O bject.ID(), ShouldResemble,
488 tree.GetChild("sub/blob" ).Object.ID())
489 So(loaded.GetChild("sub/blob").O bject, ShouldHaveSameTypeAs,
490 (*EmptyObject)(nil))
491 })
492
493 Convey("removing a tree (maybeMissing)", func() {
494 mObjID := tree.GetChild("maybeMi ssing").Object.ID()
495 delete(s, *mObjID)
496
497 Convey("missingErr", func() {
498 _, err := LT(id, false, true)
499 So(err, ShouldNotBeNil)
500 })
501
502 Convey("allowMissing", func() {
503 loaded, err := LT(id, fa lse, false)
504 So(err, ShouldBeNil)
505
506 Println(loaded.GetChild( "maybeMissing"))
507 So(loaded.GetChild("mayb eMissing").Object, ShouldHaveSameTypeAs, &EmptyObject{})
508 So(loaded.GetChild("mayb eMissing").Object.ID(), ShouldResemble, mObjID)
509 })
510 })
511 })
512
513 Convey("withBlobs", func() {
514 Convey("missingErr (succeeds)", func() {
515 loaded, err := LT(id, true, true )
516 So(err, ShouldBeNil)
517 loaded.RawString()
518 So(loaded.Complete(), ShouldBeTr ue)
519 So(loaded, ShouldResemble, tree)
520
521 Convey("also works from a commit object", func() {
522 c, err := NewCommitFromR aw([]byte(fmt.Sprintf(`tree %s
523 author Jane Janerton <bob@chromium.org> 123456789 +0000
524 committer Bob Boberton <bob@chromium.org> 123456789 +0000
525
526 Super cool tree commit`, tree.ID())))
527 So(err, ShouldBeNil)
528 s.Intern(c)
529 cloaded, err := LT(c.ID( ), true, true)
530 So(cloaded.Complete(), S houldBeTrue)
531 So(cloaded, ShouldResemb le, loaded)
532
533 })
534
535 Convey("removing a blob (maybeMi ssing/blob)", func() {
536 mObjID := tree.GetChild( "maybeMissing/blob").Object.ID()
537 delete(s, *mObjID)
538 So(s.HasObjectID(mObjID) , ShouldBeFalse)
539
540 Convey("missingErr", fun c() {
541 _, err := LT(id, true, true)
542 So(err, ShouldNo tBeNil)
543 })
544
545 Convey("allowMissing", f unc() {
546 loaded, err := L T(id, true, false)
547 So(err, ShouldBe Nil)
548 So(loaded.GetChi ld("maybeMissing/blob").Object, ShouldHaveSameTypeAs, &EmptyObject{})
549 So(loaded.GetChi ld("maybeMissing/blob").Object.ID(), ShouldResemble, mObjID)
550 })
551
552 })
553 })
554 })
555 })
556 })
557 })
558 }
OLDNEW
« no previous file with comments | « go/src/infra/libs/git/treeDiff.go ('k') | go/src/infra/libs/git/types.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698