-
Notifications
You must be signed in to change notification settings - Fork 95
Expand file tree
/
Copy pathcpp_test.go
More file actions
206 lines (179 loc) · 5.38 KB
/
Copy pathcpp_test.go
File metadata and controls
206 lines (179 loc) · 5.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package languages
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zzet/gortex/internal/graph"
)
func TestCppExtractor_Function(t *testing.T) {
src := []byte(`#include <iostream>
void greet(const std::string& name) {
std::cout << "Hello " << name << std::endl;
}
`)
e := NewCppExtractor()
result, err := e.Extract("main.cpp", src)
require.NoError(t, err)
funcs := nodesOfKind(result.Nodes, graph.KindFunction)
assert.GreaterOrEqual(t, len(funcs), 1)
assert.Equal(t, "greet", funcs[0].Name)
}
func TestCppExtractor_Class(t *testing.T) {
src := []byte(`class Point {
public:
int x, y;
Point(int x, int y) : x(x), y(y) {}
int distance() {
return x * x + y * y;
}
};
`)
e := NewCppExtractor()
result, err := e.Extract("point.cpp", src)
require.NoError(t, err)
types := nodesOfKind(result.Nodes, graph.KindType)
assert.GreaterOrEqual(t, len(types), 1)
assert.Equal(t, "Point", types[0].Name)
methods := nodesOfKind(result.Nodes, graph.KindMethod)
assert.GreaterOrEqual(t, len(methods), 1)
// Check MemberOf edges point to class.
memberEdges := edgesOfKind(result.Edges, graph.EdgeMemberOf)
assert.GreaterOrEqual(t, len(memberEdges), 1)
for _, edge := range memberEdges {
assert.Equal(t, "point.cpp::Point", edge.To)
}
}
func TestCppExtractor_Struct(t *testing.T) {
src := []byte(`struct Vec3 {
float x, y, z;
};
`)
e := NewCppExtractor()
result, err := e.Extract("vec.cpp", src)
require.NoError(t, err)
types := nodesOfKind(result.Nodes, graph.KindType)
require.Len(t, types, 1)
assert.Equal(t, "Vec3", types[0].Name)
}
func TestCppExtractor_Include(t *testing.T) {
src := []byte(`#include <iostream>
#include "mylib.h"
`)
e := NewCppExtractor()
result, err := e.Extract("main.cpp", src)
require.NoError(t, err)
imports := edgesOfKind(result.Edges, graph.EdgeImports)
assert.Len(t, imports, 2)
}
func TestCppExtractor_Namespace(t *testing.T) {
src := []byte(`namespace math {
int add(int a, int b) {
return a + b;
}
}
`)
e := NewCppExtractor()
result, err := e.Extract("math.cpp", src)
require.NoError(t, err)
pkgs := nodesOfKind(result.Nodes, graph.KindPackage)
require.Len(t, pkgs, 1)
assert.Equal(t, "math", pkgs[0].Name)
}
func TestCppExtractor_Enum(t *testing.T) {
src := []byte(`enum class Color {
Red,
Green,
Blue
};
`)
e := NewCppExtractor()
result, err := e.Extract("color.cpp", src)
require.NoError(t, err)
types := nodesOfKind(result.Nodes, graph.KindType)
require.Len(t, types, 1)
assert.Equal(t, "Color", types[0].Name)
}
func TestCppExtractor_Calls(t *testing.T) {
src := []byte(`void greet() {}
void run() {
greet();
}
`)
e := NewCppExtractor()
result, err := e.Extract("main.cpp", src)
require.NoError(t, err)
calls := edgesOfKind(result.Edges, graph.EdgeCalls)
assert.GreaterOrEqual(t, len(calls), 1)
}
func TestCppExtractor_Extensions(t *testing.T) {
e := NewCppExtractor()
assert.Equal(t, "cpp", e.Language())
exts := e.Extensions()
assert.Contains(t, exts, ".cpp")
assert.Contains(t, exts, ".cc")
assert.Contains(t, exts, ".cxx")
assert.Contains(t, exts, ".hpp")
assert.NotContains(t, exts, ".h")
}
func TestCppExtractor_FnValueAddressOf(t *testing.T) {
src := []byte("void handler() {}\n" +
"struct Foo { void method() {} };\n" +
"void run() {\n" +
" reg(&handler);\n" +
" bind(&Foo::method);\n" +
"}\n")
res, err := NewCppExtractor().Extract("s.cpp", src)
require.NoError(t, err)
forms := map[string]string{} // fn_value_name -> fn_ref_form
for _, e := range res.Edges {
if e.Meta == nil {
continue
}
if v, _ := e.Meta["via"].(string); v != "callback_candidate" {
continue
}
if name, _ := e.Meta["fn_value_name"].(string); name != "" {
form, _ := e.Meta["fn_ref_form"].(string)
forms[name] = form
assert.Equal(t, "s.cpp::run", e.From, "captured in the enclosing function")
}
}
if _, ok := forms["handler"]; !ok {
t.Errorf("register(&handler) should capture handler as a function value (got %v)", forms)
}
if _, ok := forms["Foo::method"]; !ok {
t.Errorf("bind(&Foo::method) should capture Foo::method as a function value (got %v)", forms)
}
assert.Equal(t, "address_of", forms["handler"], "&handler is an address-of form")
assert.Equal(t, "address_of", forms["Foo::method"], "&Foo::method is an address-of form")
}
func TestCppExtractor_FactoryChainReceiver(t *testing.T) {
src := []byte("struct Widget { Widget withX() { return *this; } };\n" +
"Widget builder() { return Widget(); }\n" +
"void run() {\n" +
" builder().withX().build();\n" +
"}\n")
res, err := NewCppExtractor().Extract("w.cpp", src)
require.NoError(t, err)
var withX, build *graph.Edge
for _, e := range res.Edges {
if e.Kind != graph.EdgeCalls {
continue
}
switch e.To {
case "unresolved::*.withX":
withX = e
case "unresolved::*.build":
build = e
}
}
require.NotNil(t, withX, "withX() call edge")
require.NotNil(t, build, "build() call edge")
// builder() is a typed factory, so withX()'s receiver resolves to Widget.
assert.Equal(t, "Widget", withX.Meta["receiver_type"], "factory base resolves the chained receiver type")
// build()'s hop (withX) is not a typed node here, so the chain receiver
// expression is preserved for the graph-aware resolver to complete.
if got, _ := build.Meta["receiver_expr"].(string); got != "builder().withX()" {
t.Errorf("receiver_expr = %q, want builder().withX()", got)
}
}