github.com/fairyhunter13/air@v1.40.5/runner/util_test.go (about) 1 package runner 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "reflect" 10 "runtime" 11 "strconv" 12 "strings" 13 "syscall" 14 "testing" 15 "time" 16 17 "github.com/stretchr/testify/assert" 18 ) 19 20 func TestIsDirRootPath(t *testing.T) { 21 result := isDir(".") 22 if result != true { 23 t.Errorf("expected '%t' but got '%t'", true, result) 24 } 25 } 26 27 func TestIsDirMainFile(t *testing.T) { 28 result := isDir("main.go") 29 if result != false { 30 t.Errorf("expected '%t' but got '%t'", true, result) 31 } 32 } 33 34 func TestIsDirFileNot(t *testing.T) { 35 result := isDir("main.go") 36 if result != false { 37 t.Errorf("expected '%t' but got '%t'", true, result) 38 } 39 } 40 41 func TestExpandPathWithDot(t *testing.T) { 42 path, _ := expandPath(".") 43 wd, _ := os.Getwd() 44 if path != wd { 45 t.Errorf("expected '%s' but got '%s'", wd, path) 46 } 47 } 48 49 func TestExpandPathWithHomePath(t *testing.T) { 50 path := "~/.conf" 51 result, _ := expandPath(path) 52 home := os.Getenv("HOME") 53 want := home + path[1:] 54 if result != want { 55 t.Errorf("expected '%s' but got '%s'", want, result) 56 } 57 } 58 59 func TestFileChecksum(t *testing.T) { 60 tests := []struct { 61 name string 62 fileContents []byte 63 expectedChecksum string 64 expectedChecksumError string 65 }{ 66 { 67 name: "empty", 68 fileContents: []byte(``), 69 expectedChecksum: "", 70 expectedChecksumError: "empty file, forcing rebuild without updating checksum", 71 }, 72 { 73 name: "simple", 74 fileContents: []byte(`foo`), 75 expectedChecksum: "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", 76 expectedChecksumError: "", 77 }, 78 { 79 name: "binary", 80 fileContents: []byte{0xF}, // invalid UTF-8 codepoint 81 expectedChecksum: "dc0e9c3658a1a3ed1ec94274d8b19925c93e1abb7ddba294923ad9bde30f8cb8", 82 expectedChecksumError: "", 83 }, 84 } 85 86 for _, test := range tests { 87 t.Run(test.name, func(t *testing.T) { 88 f, err := os.CreateTemp("", "") 89 if err != nil { 90 t.Fatalf("couldn't create temp file for test: %v", err) 91 } 92 93 defer func() { 94 if err := f.Close(); err != nil { 95 t.Errorf("error closing temp file: %v", err) 96 } 97 if err := os.Remove(f.Name()); err != nil { 98 t.Errorf("error removing temp file: %v", err) 99 } 100 }() 101 102 _, err = f.Write(test.fileContents) 103 if err != nil { 104 t.Fatalf("couldn't write to temp file for test: %v", err) 105 } 106 107 checksum, err := fileChecksum(f.Name()) 108 if err != nil && err.Error() != test.expectedChecksumError { 109 t.Errorf("expected '%s' but got '%s'", test.expectedChecksumError, err.Error()) 110 } 111 112 if checksum != test.expectedChecksum { 113 t.Errorf("expected '%s' but got '%s'", test.expectedChecksum, checksum) 114 } 115 }) 116 } 117 } 118 119 func TestChecksumMap(t *testing.T) { 120 m := &checksumMap{m: make(map[string]string, 3)} 121 122 if !m.updateFileChecksum("foo.txt", "abcxyz") { 123 t.Errorf("expected no entry for foo.txt, but had one") 124 } 125 126 if m.updateFileChecksum("foo.txt", "abcxyz") { 127 t.Errorf("expected matching entry for foo.txt") 128 } 129 130 if !m.updateFileChecksum("foo.txt", "123456") { 131 t.Errorf("expected matching entry for foo.txt") 132 } 133 134 if !m.updateFileChecksum("bar.txt", "123456") { 135 t.Errorf("expected no entry for bar.txt, but had one") 136 } 137 } 138 139 func TestAdaptToVariousPlatforms(t *testing.T) { 140 config := &Config{ 141 Build: cfgBuild{ 142 Bin: "tmp\\main.exe -dev", 143 }, 144 } 145 adaptToVariousPlatforms(config) 146 if config.Build.Bin != "tmp\\main.exe -dev" { 147 t.Errorf("expected '%s' but got '%s'", "tmp\\main.exe -dev", config.Build.Bin) 148 } 149 } 150 151 func Test_killCmd_no_process(t *testing.T) { 152 e := Engine{ 153 config: &Config{ 154 Build: cfgBuild{ 155 SendInterrupt: false, 156 }, 157 }, 158 } 159 _, err := e.killCmd(&exec.Cmd{ 160 Process: &os.Process{ 161 Pid: 9999, 162 }, 163 }) 164 if err == nil { 165 t.Errorf("expected error but got none") 166 } 167 if !errors.Is(err, syscall.ESRCH) { 168 t.Errorf("expected '%s' but got '%s'", syscall.ESRCH, errors.Unwrap(err)) 169 } 170 } 171 172 func Test_killCmd_SendInterrupt_false(t *testing.T) { 173 _, b, _, _ := runtime.Caller(0) 174 175 // Root folder of this project 176 dir := filepath.Dir(b) 177 err := os.Chdir(dir) 178 if err != nil { 179 t.Fatalf("couldn't change directory: %v", err) 180 } 181 182 // clean file before test 183 os.Remove("pid") 184 defer os.Remove("pid") 185 e := Engine{ 186 config: &Config{ 187 Build: cfgBuild{ 188 SendInterrupt: false, 189 }, 190 }, 191 } 192 startChan := make(chan struct { 193 pid int 194 cmd *exec.Cmd 195 }) 196 go func() { 197 cmd, _, _, err := e.startCmd("sh _testdata/run-many-processes.sh") 198 if err != nil { 199 t.Errorf("failed to start command: %v", err) 200 return 201 } 202 pid := cmd.Process.Pid 203 t.Logf("process pid is %v", pid) 204 startChan <- struct { 205 pid int 206 cmd *exec.Cmd 207 }{pid: pid, cmd: cmd} 208 cmd.Wait() 209 t.Logf("wait finished") 210 }() 211 resp := <-startChan 212 t.Logf("process started. checking pid %v", resp.pid) 213 time.Sleep(2 * time.Second) 214 t.Logf("%v", resp.cmd.Process.Pid) 215 pid, err := e.killCmd(resp.cmd) 216 if err != nil { 217 t.Fatalf("failed to kill command: %v", err) 218 } 219 t.Logf("%v was been killed", pid) 220 // check processes were being killed 221 // read pids from file 222 bytesRead, _ := os.ReadFile("pid") 223 lines := strings.Split(string(bytesRead), "\n") 224 for _, line := range lines { 225 _, err := strconv.Atoi(line) 226 if err != nil { 227 t.Logf("failed to covert str to int %v", err) 228 continue 229 } 230 _, err = exec.Command("ps", "-p", line, "-o", "comm= ").Output() 231 if err == nil { 232 t.Fatalf("process should be killed %v", line) 233 } 234 } 235 } 236 237 func TestGetStructureFieldTagMap(t *testing.T) { 238 c := Config{} 239 tagMap := flatConfig(c) 240 for _, i2 := range tagMap { 241 fmt.Printf("%v\n", i2.fieldPath) 242 } 243 } 244 245 func TestSetStructValue(t *testing.T) { 246 c := Config{} 247 v := reflect.ValueOf(&c) 248 setValue2Struct(v, "TmpDir", "asdasd") 249 assert.Equal(t, "asdasd", c.TmpDir) 250 } 251 252 func TestNestStructValue(t *testing.T) { 253 c := Config{} 254 v := reflect.ValueOf(&c) 255 setValue2Struct(v, "Build.Cmd", "asdasd") 256 assert.Equal(t, "asdasd", c.Build.Cmd) 257 } 258 259 func TestNestStructArrayValue(t *testing.T) { 260 c := Config{} 261 v := reflect.ValueOf(&c) 262 setValue2Struct(v, "Build.ExcludeDir", "dir1,dir2") 263 assert.Equal(t, []string{"dir1", "dir2"}, c.Build.ExcludeDir) 264 } 265 266 func TestNestStructArrayValueOverride(t *testing.T) { 267 c := Config{ 268 Build: cfgBuild{ 269 ExcludeDir: []string{"default1", "default2"}, 270 }, 271 } 272 v := reflect.ValueOf(&c) 273 setValue2Struct(v, "Build.ExcludeDir", "dir1,dir2") 274 assert.Equal(t, []string{"dir1", "dir2"}, c.Build.ExcludeDir) 275 }