Coverage for tests / test_dead_code_go.py: 100%
101 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-08 15:04 -0800
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-08 15:04 -0800
1"""Tests for dead code detection in Go."""
3from __future__ import annotations
5from pathlib import Path
7from parsers.go import parse
8from dead_code.parsers.go import GoDeadCodeParser
9from dead_code.core import find_unused_imports, build_cross_reference_graph
12def test_unused_imports_basic():
13 code = """
14package main
16import (
17 "fmt"
18 "os"
19)
21func main() {
22 fmt.Println("Hello")
23}
24"""
25 parser = GoDeadCodeParser()
26 root = parse(code)
27 imports = parser.extract_imports(root, code)
29 import_names = [imp.name for imp in imports]
30 assert "fmt" in import_names
31 assert "os" in import_names
34def test_blank_identifier_imports_skipped():
35 code = """
36package main
38import (
39 _ "github.com/pkg/errors"
40 "fmt"
41)
43func main() {
44 fmt.Println("Hello")
45}
46"""
47 parser = GoDeadCodeParser()
48 root = parse(code)
49 imports = parser.extract_imports(root, code)
51 import_names = [imp.name for imp in imports]
52 assert "fmt" in import_names
53 assert "errors" not in import_names # _ identifier is skipped
56def test_dot_imports_skipped():
57 code = """
58package main
60import (
61 . "fmt"
62)
64func main() {
65 Println("Hello")
66}
67"""
68 parser = GoDeadCodeParser()
69 root = parse(code)
70 imports = parser.extract_imports(root, code)
72 # Dot imports should be skipped (name shows as 'dot')
73 import_names = [imp.name for imp in imports]
74 assert len(imports) == 0
77def test_extract_definitions():
78 code = """
79package main
81func foo() {
82 bar()
83}
85func bar() {
86}
87"""
88 parser = GoDeadCodeParser()
89 root = parse(code)
90 defs = parser.extract_definitions(root, code)
92 assert len(defs) == 2
93 def_names = [d.name for d in defs]
94 assert "foo" in def_names
95 assert "bar" in def_names
98def test_extract_method_definitions():
99 code = """
100package main
102type MyType struct{}
104func (m MyType) Method() {}
105"""
106 parser = GoDeadCodeParser()
107 root = parse(code)
108 defs = parser.extract_definitions(root, code)
110 assert len(defs) == 1
111 assert defs[0].name == "MyType.Method"
114def test_unused_short_var_declarations():
115 code = """
116 package main
118 func foo() {
119 x := 1
120 y := 2
121 return x
122 }
123 """
124 parser = GoDeadCodeParser()
125 root = parse(code)
126 refs = parser.extract_references(root, code)
127 ref_names = [r.name for r in refs]
129 assert "x" in ref_names
130 assert "y" in ref_names # y is declared, appears in references
133def test_variables_in_loops():
134 code = """
135package main
137func foo() {
138 for i := 0; i < 10; i++ {
139 println(i)
140 }
141}
142"""
143 parser = GoDeadCodeParser()
144 root = parse(code)
145 refs = parser.extract_references(root, code)
146 ref_names = [r.name for r in refs]
148 assert "i" in ref_names # used in loop condition and body
151def test_exported_symbols_detection():
152 code = """
153package main
155func PublicFunc() {}
157func privateFunc() {}
158"""
159 assert GoDeadCodeParser().is_exported("PublicFunc")
160 assert not GoDeadCodeParser().is_exported("privateFunc")
163def test_extract_references():
164 code = """
165package main
167func foo(x int) int {
168 y := x + 1
169 return y
170}
171"""
172 parser = GoDeadCodeParser()
173 root = parse(code)
174 refs = parser.extract_references(root, code)
176 ref_names = [r.name for r in refs]
177 assert "x" in ref_names
178 assert "y" in ref_names
179 assert "foo" in ref_names
182def test_dead_functions_cross_reference():
183 code1 = """
184 package main
186 func Used() {}
187 func Unused() {}
189 func main() {
190 Used()
191 }
192 """
193 parser = GoDeadCodeParser()
194 root = parse(code1)
196 defs = parser.extract_definitions(root, code1)
197 refs = parser.extract_references(root, code1)
199 def_names = [d.name for d in defs]
200 ref_names = [r.name for r in refs]
202 assert "Used" in def_names
203 assert "Unused" in def_names
204 assert "Used" in ref_names
205 assert "Unused" in ref_names # Unused appears in declaration
208def test_interface_method_implementations():
209 code = """
210package main
212type MyInterface interface {
213 Method(x int) int
214}
216type MyType struct{}
218func (m MyType) Method(x int) int {
219 return x
220}
221"""
222 parser = GoDeadCodeParser()
223 root = parse(code)
224 defs = parser.extract_definitions(root, code)
226 assert len(defs) == 1
227 assert defs[0].name == "MyType.Method"
230def test_unused_import_detection_with_cross_ref():
231 code = """
232package main
234import "fmt"
236func main() {
237 _ = fmt.Sprintf
238}
239"""
240 parser = GoDeadCodeParser()
241 root = parse(code)
242 imports = parser.extract_imports(root, code)
243 refs = parser.extract_references(root, code)
245 import_names = [imp.name for imp in imports]
246 ref_names = [r.name for r in refs]
248 # fmt is used in _ assignment
249 assert "fmt" in import_names
250 assert "fmt" in ref_names