xref: /aosp_15_r20/external/skia/bazel/exporter/cmake_exporter_test.go (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1// Copyright 2022 Google LLC
2//
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5
6package exporter
7
8import (
9	"bytes"
10	"path/filepath"
11	"testing"
12
13	"github.com/stretchr/testify/assert"
14	"github.com/stretchr/testify/mock"
15	"github.com/stretchr/testify/require"
16	"go.skia.org/infra/go/skerr"
17	"go.skia.org/skia/bazel/exporter/build_proto/analysis_v2"
18	"go.skia.org/skia/bazel/exporter/interfaces/mocks"
19	"google.golang.org/protobuf/encoding/prototext"
20)
21
22const testWorkspaceDir = "/path/to/workspace"
23const testCMakeOutFname = "/not/necessarily/in/workspace/CMakeLists.txt"
24
25// This input test data (in textproto format) started as output of
26// a bazel cquery call - like:
27//
28//	bazel cquery --noimplicit_deps 'kind("rule", deps(//:core))' --output textproto
29//
30// and then hand edited to create a small valid query result with specific
31// files, copts, and other cc_library/cc_binary rule attributes.
32const textProto = `results {
33	target {
34		type: RULE
35		rule {
36		  name: "//src/libs:sum"
37		  rule_class: "cc_library"
38		  location: "/path/to/workspace/src/libs/BUILD.bazel:8:11"
39		  attribute {
40			name: "copts"
41			type: STRING_LIST
42			string_list_value: "-O2"
43			explicitly_specified: true
44			nodep: false
45		  }
46		  attribute {
47			name: "defines"
48			type: STRING_LIST
49			string_list_value: "SUMDEF"
50			explicitly_specified: false
51			nodep: false
52		  }
53		  attribute {
54			name: "includes"
55			type: STRING_LIST
56			string_list_value: "."
57			explicitly_specified: false
58			nodep: false
59		  }
60		  attribute {
61			name: "linkopts"
62			type: STRING_LIST
63			string_list_value: "-L/library/dir"
64			explicitly_specified: false
65			nodep: false
66		  }
67		  attribute {
68			name: "name"
69			type: STRING
70			string_value: "sum"
71			explicitly_specified: true
72			nodep: false
73		  }
74		  attribute {
75			  name: "srcs"
76			  type: LABEL_LIST
77			  string_list_value: "//src/libs:sum.cpp"
78			  explicitly_specified: true
79			  nodep: false
80		  }
81		  attribute {
82			name: "hdrs"
83			type: LABEL_LIST
84			string_list_value: "//src/libs:sum.h"
85			explicitly_specified: true
86			nodep: false
87		  }
88		  attribute {
89			name: "visibility"
90			type: STRING_LIST
91			string_list_value: "//visibility:public"
92			explicitly_specified: true
93			nodep: true
94		  }
95		}
96	  },
97	}
98	results {
99	  target {
100	  type: RULE
101	  rule {
102		name: "//src/apps:hello"
103		rule_class: "cc_binary"
104		location: "/path/to/workspace/src/apps/BUILD.bazel:8:11"
105		attribute {
106		  name: "copts"
107		  type: STRING_LIST
108		  string_list_value: "-O1"
109		  explicitly_specified: true
110		  nodep: false
111		}
112		attribute {
113		  name: "defines"
114		  type: STRING_LIST
115		  string_list_value: "APPDEF"
116		  explicitly_specified: false
117		  nodep: false
118		}
119		attribute {
120		  name: "linkopts"
121		  type: STRING_LIST
122		  string_list_value: "-L/app/dir"
123		  explicitly_specified: false
124		  nodep: false
125		}
126		attribute {
127		  name: "name"
128		  type: STRING
129		  string_value: "hello"
130		  explicitly_specified: true
131		  nodep: false
132		}
133		attribute {
134			name: "srcs"
135			type: LABEL_LIST
136			string_list_value: "//src/apps:hello-world.cpp"
137			explicitly_specified: true
138			nodep: false
139		}
140		attribute {
141			name: "deps"
142			type: LABEL_LIST
143			string_list_value: "//src/libs:sum"
144			explicitly_specified: false
145			nodep: false
146		}
147		attribute {
148		  name: "visibility"
149		  type: STRING_LIST
150		  string_list_value: "//visibility:public"
151		  explicitly_specified: true
152		  nodep: true
153		}
154	  }
155	}
156  }`
157
158func TestExport_QueryReadError_ReturnsError(t *testing.T) {
159	fs := mocks.NewFileSystem(t)
160	e := NewCMakeExporter("projName", testWorkspaceDir, testCMakeOutFname, fs)
161	qcmd := mocks.NewQueryCommand(t)
162	qcmd.On("Read", mock.Anything).Return([]byte{}, skerr.Fmt("expected error"))
163	err := e.Export(qcmd)
164	assert.Error(t, err)
165}
166
167func TestExport_InvalidProtobuf_ReturnsError(t *testing.T) {
168	fs := mocks.NewFileSystem(t)
169	e := NewCMakeExporter("projName", testWorkspaceDir, testCMakeOutFname, fs)
170	qcmd := mocks.NewQueryCommand(t)
171	qcmd.On("Read", mock.Anything).Return(make([]byte, 50), skerr.Fmt("empty data"))
172	err := e.Export(qcmd)
173	assert.Error(t, err)
174}
175
176func TestExport_ValidProtobuf_Success(t *testing.T) {
177	protoData, err := textProtoToProtobuf(textProto)
178	require.NoError(t, err)
179
180	var contents bytes.Buffer
181	fs := mocks.NewFileSystem(t)
182	fs.On("OpenFile", mock.Anything).Once().Run(func(args mock.Arguments) {
183		assert.True(t, filepath.IsAbs(args.String(0)))
184		assert.Equal(t, args.String(0), testCMakeOutFname)
185	}).Return(&contents, nil)
186	e := NewCMakeExporter("projName", testWorkspaceDir, testCMakeOutFname, fs)
187	qcmd := mocks.NewQueryCommand(t)
188	qcmd.On("Read", mock.Anything).Return(protoData, nil)
189	err = e.Export(qcmd)
190	require.NoError(t, err)
191
192	// This expected CMake output text is created by hand.
193	const expected = `# DO NOT EDIT: This file is auto-generated.
194cmake_minimum_required(VERSION 3.13)
195
196project(projName LANGUAGES C CXX)
197
198set(DEFAULT_COMPILE_FLAGS_MACOS "-std=c++17 -Wno-psabi --target=arm64-apple-macos11")
199set(DEFAULT_COMPILE_FLAGS_LINUX "-std=c++17 -Wno-psabi -Wno-attributes")
200
201if (APPLE)
202  set(DEFAULT_COMPILE_FLAGS "${DEFAULT_COMPILE_FLAGS_MACOS}")
203else()
204  set(DEFAULT_COMPILE_FLAGS "${DEFAULT_COMPILE_FLAGS_LINUX}")
205endif()
206
207
208# //src/apps:hello
209add_executable(src_apps_hello "")
210target_sources(src_apps_hello
211  PRIVATE
212    # Sources:
213    "${CMAKE_SOURCE_DIR}/src/apps/hello-world.cpp"
214)
215set_target_properties(src_apps_hello PROPERTIES COMPILE_FLAGS
216  "${DEFAULT_COMPILE_FLAGS} -O1"
217)
218set_target_properties(src_apps_hello PROPERTIES LINK_FLAGS
219  "-L/app/dir"
220)
221set_target_properties(src_apps_hello PROPERTIES COMPILE_DEFINITIONS
222  "APPDEF;SUMDEF"
223)
224set_target_properties(src_apps_hello PROPERTIES INCLUDE_DIRECTORIES
225  "${CMAKE_SOURCE_DIR}/src/libs;${CMAKE_SOURCE_DIR}"
226)
227
228# //src/libs:sum
229add_library(src_libs_sum "")
230target_sources(src_libs_sum
231  PRIVATE
232    # Sources:
233    "${CMAKE_SOURCE_DIR}/src/libs/sum.cpp"
234    # Headers:
235    "${CMAKE_SOURCE_DIR}/src/libs/sum.h"
236)
237set_target_properties(src_libs_sum PROPERTIES COMPILE_FLAGS
238  "${DEFAULT_COMPILE_FLAGS} -O2"
239)
240set_target_properties(src_libs_sum PROPERTIES LINK_FLAGS
241  "-L/library/dir"
242)
243set_target_properties(src_libs_sum PROPERTIES COMPILE_DEFINITIONS
244  "SUMDEF"
245)
246set_target_properties(src_libs_sum PROPERTIES INCLUDE_DIRECTORIES
247  "${CMAKE_SOURCE_DIR}/src/libs;${CMAKE_SOURCE_DIR}"
248)
249`
250
251	assert.Equal(t, expected, contents.String())
252}
253
254func TestGetRuleCopts_CoptsExists_Success(t *testing.T) {
255	qr := analysis_v2.CqueryResult{}
256	err := prototext.Unmarshal([]byte(textProto), &qr)
257	require.NoError(t, err)
258
259	r := findRule(&qr, "//src/apps:hello")
260	require.NotNil(t, r)
261
262	copts, err := getRuleCopts(r)
263	require.NoError(t, err)
264	assert.Equal(t, []string{"${DEFAULT_COMPILE_FLAGS}", "-O1"}, copts)
265}
266