github.com/btwiuse/jiri@v0.0.0-20191125065820-53353bcfef54/cmd/jiri/generate-gitmodules_test.go (about) 1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bufio" 9 "bytes" 10 "encoding/hex" 11 "fmt" 12 "io/ioutil" 13 "os" 14 "path" 15 "path/filepath" 16 "strings" 17 "testing" 18 19 "github.com/btwiuse/jiri/project" 20 ) 21 22 func TestPrefixTree(t *testing.T) { 23 _, fakeroot, cleanup := setupUniverse(t) 24 defer cleanup() 25 26 projects := []project.Project{ 27 project.Project{Name: "root", Path: "."}, 28 project.Project{Name: "a", Path: "a"}, 29 project.Project{Name: "b", Path: "b"}, 30 project.Project{Name: "c/d/e", Path: "c/d/e"}, 31 project.Project{Name: "c/d/f", Path: "c/d/f"}, 32 project.Project{Name: "c/d", Path: "c/d"}, 33 project.Project{Name: "c", Path: "c"}, 34 } 35 expectedDropped := []project.Project{ 36 projects[0], 37 projects[3], 38 projects[4], 39 projects[5], 40 } 41 42 // Fill projects into prefix tree 43 root := projectTree{nil, make(map[string]*projectTree)} 44 dropped := make(project.Projects) 45 treeRoot := projectTreeRoot{&root, dropped} 46 for _, v := range projects { 47 if err := treeRoot.add(fakeroot.X, v); err != nil { 48 t.Errorf("adding project to prefixTree failed due to error: %v", err) 49 break 50 } 51 } 52 53 // generate logs when test failed 54 failedDropped := func() { 55 t.Logf("wrong nested projects list") 56 t.Logf("expecting: ") 57 for _, v := range expectedDropped { 58 t.Logf("\tproject:%q", v.Path) 59 } 60 t.Logf("got:") 61 for _, v := range treeRoot.dropped { 62 t.Logf("\tproject:%q", v.Path) 63 } 64 t.Fail() 65 } 66 67 // Verify nested projects 68 if len(treeRoot.dropped) != len(expectedDropped) { 69 failedDropped() 70 } 71 for _, v := range expectedDropped { 72 if _, ok := treeRoot.dropped[v.Key()]; !ok { 73 failedDropped() 74 break 75 } 76 } 77 78 // Verify the shape of prefix tree 79 if len(root.children) == 3 { 80 prefixes := []string{"a", "b", "c"} 81 for _, v := range prefixes { 82 if _, ok := root.children[v]; !ok { 83 t.Errorf("root node does not contain project %q", v) 84 } 85 } 86 for _, v := range root.children { 87 if len(v.children) != 0 { 88 t.Errorf("more than 1 level of nodes found in prefix tree") 89 } 90 } 91 } else { 92 t.Errorf("expecting %v first level nodes, but got %v", 3, len(root.children)) 93 } 94 } 95 96 func TestGitModules(t *testing.T) { 97 goldenScript := []byte(`#!/bin/sh 98 git update-index --add --cacheinfo 160000 87326c54332e5be21eda2173bb001aaee73a9ab7 "manifest" 99 git update-index --add --cacheinfo 160000 87f863bcbc7cd2177bac17c61e31093de6eeed28 "path-0" 100 git update-index --add --cacheinfo 160000 87f863bcbc7cd2177bac17c61e31093de6eeed28 "path-1" 101 git update-index --add --cacheinfo 160000 87f863bcbc7cd2177bac17c61e31093de6eeed28 "path-2"`) 102 103 goldenModule := []byte(`[submodule "manifest"] 104 branch = 87326c54332e5be21eda2173bb001aaee73a9ab7 105 path = manifest 106 url = /tmp/115893653/manifest 107 [submodule "project-0"] 108 branch = 87f863bcbc7cd2177bac17c61e31093de6eeed28 109 path = path-0 110 url = /tmp/115893653/project-0 111 [submodule "project-1"] 112 branch = 87f863bcbc7cd2177bac17c61e31093de6eeed28 113 path = path-1 114 url = /tmp/115893653/project-1 115 [submodule "project-2"] 116 branch = 87f863bcbc7cd2177bac17c61e31093de6eeed28 117 path = path-2 118 url = /tmp/115893653/project-2`) 119 120 goldenAttributes := []byte(`manifest manifest public 121 path-0 manifest public 122 path-1 manifest public 123 path-2 manifest public 124 `) 125 126 // Setup fake workspace and update $JIRI_ROOT 127 _, fakeroot, cleanup := setupUniverse(t) 128 defer cleanup() 129 if err := fakeroot.UpdateUniverse(false); err != nil { 130 t.Errorf("%v", err) 131 } 132 133 localProjects, err := project.LocalProjects(fakeroot.X, project.FullScan) 134 if err != nil { 135 t.Errorf("scanning local fake project failed due to error %v", err) 136 } 137 138 pathMap := make(map[string]project.Project) 139 for _, v := range localProjects { 140 v.Path, err = makePathRel(fakeroot.X.Root, v.Path) 141 if err != nil { 142 t.Errorf("path relativation failed due to error %v", err) 143 } 144 pathMap[v.Path] = v 145 } 146 147 tempDir, err := ioutil.TempDir("", "gitmodules") 148 if err != nil { 149 t.Errorf(".gitmodules generation failed due to error %v", err) 150 } 151 defer os.RemoveAll(tempDir) 152 153 genGitModuleFlags.genScript = path.Join(tempDir, "setup.sh") 154 err = runGenGitModule(fakeroot.X, []string{ 155 path.Join(tempDir, ".gitmodules"), 156 path.Join(tempDir, ".gitattributes"), 157 }) 158 if err != nil { 159 t.Errorf(".gitmodules generation failed due to error %v", err) 160 } 161 162 // Read and verify content of generated script 163 data, err := ioutil.ReadFile(genGitModuleFlags.genScript) 164 if err != nil { 165 t.Errorf("reading generated script file failed due to error: %v", err) 166 } 167 t.Logf("generated script content \n%s\n", string(data)) 168 169 if err := verifyScript(goldenScript, data); err != nil { 170 t.Errorf("verifying generated script failed due to error: %v", err) 171 } 172 173 // Read and verify content of generated .gitmodules file 174 data, err = ioutil.ReadFile(path.Join(tempDir, ".gitmodules")) 175 if err != nil { 176 t.Errorf("reading generated .gitmodules file failed due to error: %v", err) 177 } 178 t.Logf("generated gitmodule content \n%s\n", string(data)) 179 180 if err := verifyModules(goldenModule, data); err != nil { 181 t.Errorf("verifying generated .gitmodules failed due to error: %v", err) 182 } 183 184 // Read and verify content of generated .gitattributes file 185 data, err = ioutil.ReadFile(path.Join(tempDir, ".gitattributes")) 186 if err != nil { 187 t.Errorf("reading generated .gitattributes file failed due to error: %v", err) 188 } 189 t.Logf("generated gitattributes content \n%s\n", string(data)) 190 if bytes.Compare(data, goldenAttributes) != 0 { 191 t.Errorf("verfying generated .gitattributes failed. Expecting: %q, got %q", string(goldenAttributes), string(data)) 192 } 193 } 194 195 func readlines(data []byte) ([]string, error) { 196 var buffer bytes.Buffer 197 retLines := make([]string, 0) 198 if _, err := buffer.Write(data); err != nil { 199 return nil, err 200 } 201 scanner := bufio.NewScanner(&buffer) 202 for scanner.Scan() { 203 line := strings.TrimSpace(scanner.Text()) 204 if len(line) == 0 || line[0] == '#' { 205 continue 206 } 207 retLines = append(retLines, line) 208 } 209 return retLines, nil 210 } 211 212 func verifyModules(golden, tests []byte) error { 213 goldenLines, err := readlines(golden) 214 if err != nil { 215 return err 216 } 217 testLines, err := readlines(tests) 218 if err != nil { 219 return err 220 } 221 if len(goldenLines) != len(testLines) { 222 return fmt.Errorf("expecting %q non-empty/non-comment lines from generated .gitmodules, got %q lines", len(goldenLines), len(testLines)) 223 } 224 for i := 0; i < len(goldenLines); i++ { 225 goldenLine := goldenLines[i] 226 testLine := testLines[i] 227 if strings.HasPrefix(testLine, "branch = ") { 228 revision := testLine[len("branch = "):] 229 // revision should be 20 bytes in hex format 230 if len(revision) != 40 { 231 return fmt.Errorf("illegal revision hash in line %q", testLine) 232 } 233 if _, err := hex.DecodeString(revision); err != nil { 234 return fmt.Errorf("illegal revision hash in line %q", testLine) 235 } 236 continue 237 } 238 if strings.HasPrefix(testLine, "url = ") { 239 testPath := testLine[len("url = "):] 240 goldenPath := goldenLine[len("url = "):] 241 testPathFields := strings.Split(testPath, string(filepath.Separator)) 242 goldenPathFields := strings.Split(goldenPath, string(filepath.Separator)) 243 testPath = testPathFields[len(testPathFields)-1] 244 goldenPath = goldenPathFields[len(goldenPathFields)-1] 245 if testPath != goldenPath { 246 return fmt.Errorf("path mismatch, expecting %q, got %q", goldenPath, testPath) 247 } 248 continue 249 } 250 if goldenLine != testLine { 251 return fmt.Errorf("in generated .gitmodules file, expecting %q, got %q", goldenLine, testLine) 252 } 253 } 254 return nil 255 } 256 257 func verifyScript(golden, tests []byte) error { 258 goldenLines, err := readlines(golden) 259 if err != nil { 260 return err 261 } 262 testLines, err := readlines(tests) 263 if err != nil { 264 return err 265 } 266 if len(goldenLines) != len(testLines) { 267 return fmt.Errorf("expecting %q non-empty/non-comment lines from generated script, got %q lines", len(goldenLines), len(testLines)) 268 } 269 for i := 0; i < len(goldenLines); i++ { 270 goldenLine := goldenLines[i] 271 testLine := testLines[i] 272 goldenFields := strings.Fields(goldenLine) 273 testFields := strings.Fields(testLine) 274 if len(goldenFields) != len(testFields) { 275 return fmt.Errorf("format error at line %q in generated script, expecting something like %q", testLine, goldenLine) 276 } 277 // Any field except the revision hash should be exact match. 278 for j := 0; j < 5; j++ { 279 if goldenFields[j] != testFields[j] { 280 return fmt.Errorf("command missmatch at line %q in generated script, expecting something like %q", testLine, goldenLine) 281 } 282 } 283 if goldenFields[6] != testFields[6] { 284 return fmt.Errorf("command missmatch at line %q in generated script, expecting something like %q", testLine, goldenLine) 285 } 286 // revision should be 20 bytes in hex format 287 if len(testFields[5]) != 40 { 288 return fmt.Errorf("illegal revision hash in line %q", testLine) 289 } 290 if _, err := hex.DecodeString(testFields[5]); err != nil { 291 return fmt.Errorf("illegal revision hash in git command %q", testLine) 292 } 293 } 294 return nil 295 }