@@ -19,14 +19,57 @@ import (
19
19
"os/exec"
20
20
"path"
21
21
"path/filepath"
22
+ "slices"
23
+ "strings"
22
24
"testing"
23
25
24
26
"github.com/googleapis/librarian/internal/sidekick/internal/config"
25
27
"github.com/googleapis/librarian/internal/sidekick/internal/parser"
26
28
)
27
29
28
30
var (
29
- testdataDir , _ = filepath .Abs ("../../testdata" )
31
+ testdataDir , _ = filepath .Abs ("../../testdata" )
32
+ expectedInNosvc = []string {
33
+ "README.md" ,
34
+ "Cargo.toml" ,
35
+ path .Join ("src" , "lib.rs" ),
36
+ path .Join ("src" , "model.rs" ),
37
+ path .Join ("src" , "model" , "debug.rs" ),
38
+ path .Join ("src" , "model" , "deserialize.rs" ),
39
+ path .Join ("src" , "model" , "serialize.rs" ),
40
+ }
41
+ expectedInCrate = append (expectedInNosvc ,
42
+ path .Join ("src" , "builder.rs" ),
43
+ path .Join ("src" , "client.rs" ),
44
+ path .Join ("src" , "tracing.rs" ),
45
+ path .Join ("src" , "transport.rs" ),
46
+ path .Join ("src" , "stub.rs" ),
47
+ path .Join ("src" , "stub" , "dynamic.rs" ),
48
+ )
49
+ expectedInClient = []string {
50
+ path .Join ("mod.rs" ),
51
+ path .Join ("model.rs" ),
52
+ path .Join ("model" , "debug.rs" ),
53
+ path .Join ("model" , "deserialize.rs" ),
54
+ path .Join ("model" , "serialize.rs" ),
55
+ path .Join ("builder.rs" ),
56
+ path .Join ("client.rs" ),
57
+ path .Join ("tracing.rs" ),
58
+ path .Join ("transport.rs" ),
59
+ path .Join ("stub.rs" ),
60
+ path .Join ("stub" , "dynamic.rs" ),
61
+ }
62
+ unexpectedInClient = []string {
63
+ "README.md" ,
64
+ "Cargo.toml" ,
65
+ path .Join ("src" , "lib.rs" ),
66
+ }
67
+ expectedInModule = []string {
68
+ path .Join ("mod.rs" ),
69
+ path .Join ("debug.rs" ),
70
+ path .Join ("deserialize.rs" ),
71
+ path .Join ("serialize.rs" ),
72
+ }
30
73
)
31
74
32
75
func TestRustFromOpenAPI (t * testing.T ) {
@@ -47,7 +90,7 @@ func TestRustFromOpenAPI(t *testing.T) {
47
90
if err := Generate (model , outDir , cfg ); err != nil {
48
91
t .Fatal (err )
49
92
}
50
- for _ , expected := range [] string { "README.md" , "Cargo.toml" , "src/lib.rs" } {
93
+ for _ , expected := range expectedInCrate {
51
94
filename := path .Join (outDir , expected )
52
95
stat , err := os .Stat (filename )
53
96
if os .IsNotExist (err ) {
@@ -57,6 +100,7 @@ func TestRustFromOpenAPI(t *testing.T) {
57
100
t .Errorf ("generated files should not be executable %s: %o" , filename , stat .Mode ())
58
101
}
59
102
}
103
+ importsModelModules (t , path .Join (outDir , "src" , "model.rs" ))
60
104
}
61
105
62
106
func TestRustFromProtobuf (t * testing.T ) {
@@ -80,7 +124,91 @@ func TestRustFromProtobuf(t *testing.T) {
80
124
if err := Generate (model , outDir , cfg ); err != nil {
81
125
t .Fatal (err )
82
126
}
83
- for _ , expected := range []string {"README.md" , "Cargo.toml" , "src/lib.rs" } {
127
+ for _ , expected := range expectedInCrate {
128
+ filename := path .Join (outDir , expected )
129
+ stat , err := os .Stat (filename )
130
+ if os .IsNotExist (err ) {
131
+ t .Errorf ("missing %s: %s" , filename , err )
132
+ }
133
+ if stat .Mode ().Perm ()| 0666 != 0666 {
134
+ t .Errorf ("generated files should not be executable %s: %o" , filename , stat .Mode ())
135
+ }
136
+ }
137
+ importsModelModules (t , path .Join (outDir , "src" , "model.rs" ))
138
+ }
139
+
140
+ func TestRustClient (t * testing.T ) {
141
+ requireProtoc (t )
142
+ for _ , override := range []string {"http-client" , "grpc-client" } {
143
+ outDir := t .TempDir ()
144
+
145
+ cfg := & config.Config {
146
+ General : config.GeneralConfig {
147
+ SpecificationFormat : "protobuf" ,
148
+ ServiceConfig : "google/cloud/secretmanager/v1/secretmanager_v1.yaml" ,
149
+ SpecificationSource : "google/cloud/secretmanager/v1" ,
150
+ },
151
+ Source : map [string ]string {
152
+ "googleapis-root" : path .Join (testdataDir , "googleapis" ),
153
+ },
154
+ Codec : map [string ]string {
155
+ "copyright-year" : "2025" ,
156
+ "template-override" : path .Join ("templates" , override ),
157
+ },
158
+ }
159
+ model , err := parser .CreateModel (cfg )
160
+ if err != nil {
161
+ t .Fatal (err )
162
+ }
163
+ if err := Generate (model , outDir , cfg ); err != nil {
164
+ t .Fatal (err )
165
+ }
166
+ for _ , expected := range expectedInClient {
167
+ filename := path .Join (outDir , expected )
168
+ stat , err := os .Stat (filename )
169
+ if os .IsNotExist (err ) {
170
+ t .Errorf ("missing %s: %s" , filename , err )
171
+ }
172
+ if stat .Mode ().Perm ()| 0666 != 0666 {
173
+ t .Errorf ("generated files should not be executable %s: %o" , filename , stat .Mode ())
174
+ }
175
+ }
176
+ for _ , unexpected := range unexpectedInClient {
177
+ filename := path .Join (outDir , unexpected )
178
+ if stat , err := os .Stat (filename ); err == nil {
179
+ t .Errorf ("did not expect file %s, got=%v" , unexpected , stat )
180
+ }
181
+ }
182
+ importsModelModules (t , path .Join (outDir , "model.rs" ))
183
+ }
184
+ }
185
+
186
+ func TestRustNosvc (t * testing.T ) {
187
+ requireProtoc (t )
188
+ outDir := t .TempDir ()
189
+
190
+ cfg := & config.Config {
191
+ General : config.GeneralConfig {
192
+ SpecificationFormat : "protobuf" ,
193
+ ServiceConfig : "google/cloud/secretmanager/v1/secretmanager_v1.yaml" ,
194
+ SpecificationSource : "google/cloud/secretmanager/v1" ,
195
+ },
196
+ Source : map [string ]string {
197
+ "googleapis-root" : path .Join (testdataDir , "googleapis" ),
198
+ },
199
+ Codec : map [string ]string {
200
+ "copyright-year" : "2025" ,
201
+ "template-override" : path .Join ("templates" , "nosvc" ),
202
+ },
203
+ }
204
+ model , err := parser .CreateModel (cfg )
205
+ if err != nil {
206
+ t .Fatal (err )
207
+ }
208
+ if err := Generate (model , outDir , cfg ); err != nil {
209
+ t .Fatal (err )
210
+ }
211
+ for _ , expected := range expectedInNosvc {
84
212
filename := path .Join (outDir , expected )
85
213
stat , err := os .Stat (filename )
86
214
if os .IsNotExist (err ) {
@@ -90,6 +218,7 @@ func TestRustFromProtobuf(t *testing.T) {
90
218
t .Errorf ("generated files should not be executable %s: %o" , filename , stat .Mode ())
91
219
}
92
220
}
221
+ importsModelModules (t , path .Join (outDir , "src" , "model.rs" ))
93
222
}
94
223
95
224
func TestRustModuleRpc (t * testing.T ) {
@@ -118,7 +247,7 @@ func TestRustModuleRpc(t *testing.T) {
118
247
t .Fatal (err )
119
248
}
120
249
121
- for _ , expected := range [] string { "mod.rs" } {
250
+ for _ , expected := range expectedInModule {
122
251
filename := path .Join (outDir , "rpc" , expected )
123
252
stat , err := os .Stat (filename )
124
253
if os .IsNotExist (err ) {
@@ -128,6 +257,7 @@ func TestRustModuleRpc(t *testing.T) {
128
257
t .Errorf ("generated files should not be executable %s: %o" , filename , stat .Mode ())
129
258
}
130
259
}
260
+ importsModelModules (t , path .Join (outDir , "rpc" , "mod.rs" ))
131
261
}
132
262
133
263
func TestRustBootstrapWkt (t * testing.T ) {
@@ -157,7 +287,7 @@ func TestRustBootstrapWkt(t *testing.T) {
157
287
t .Fatal (err )
158
288
}
159
289
160
- for _ , expected := range [] string { "mod.rs" } {
290
+ for _ , expected := range expectedInModule {
161
291
filename := path .Join (outDir , "wkt" , expected )
162
292
stat , err := os .Stat (filename )
163
293
if os .IsNotExist (err ) {
@@ -169,6 +299,20 @@ func TestRustBootstrapWkt(t *testing.T) {
169
299
}
170
300
}
171
301
302
+ func importsModelModules (t * testing.T , filename string ) {
303
+ t .Helper ()
304
+ contents , err := os .ReadFile (filename )
305
+ if err != nil {
306
+ t .Fatal (err )
307
+ }
308
+ lines := strings .Split (string (contents ), "\n " )
309
+ for _ , want := range []string {"mod debug;" , "mod serialize;" , "mod deserialize;" } {
310
+ if ! slices .Contains (lines , want ) {
311
+ t .Errorf ("expected file %s to have a line matching %q, got:\n %s" , filename , want , contents )
312
+ }
313
+ }
314
+ }
315
+
172
316
func requireProtoc (t * testing.T ) {
173
317
t .Helper ()
174
318
if _ , err := exec .LookPath ("protoc" ); err != nil {
0 commit comments