| // Copyright 2022 Google LLC |
| // |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package exporter |
| |
| import ( |
| "bytes" |
| "path/filepath" |
| "testing" |
| |
| "github.com/stretchr/testify/assert" |
| "github.com/stretchr/testify/mock" |
| "github.com/stretchr/testify/require" |
| "go.skia.org/infra/go/skerr" |
| "go.skia.org/skia/bazel/exporter/build_proto/analysis_v2" |
| "go.skia.org/skia/bazel/exporter/interfaces/mocks" |
| "google.golang.org/protobuf/encoding/prototext" |
| ) |
| |
| const testWorkspaceDir = "/path/to/workspace" |
| const testCMakeOutFname = "/not/necessarily/in/workspace/CMakeLists.txt" |
| |
| // This input test data (in textproto format) started as output of |
| // a bazel cquery call - like: |
| // |
| // bazel cquery --noimplicit_deps 'kind("rule", deps(//:skia_public))' --output textproto |
| // |
| // and then hand edited to create a small valid query result with specific |
| // files, copts, and other cc_library/cc_binary rule attributes. |
| const textProto = `results { |
| target { |
| type: RULE |
| rule { |
| name: "//src/libs:sum" |
| rule_class: "cc_library" |
| location: "/path/to/workspace/src/libs/BUILD.bazel:8:11" |
| attribute { |
| name: "copts" |
| type: STRING_LIST |
| string_list_value: "-O2" |
| explicitly_specified: true |
| nodep: false |
| } |
| attribute { |
| name: "defines" |
| type: STRING_LIST |
| string_list_value: "SUMDEF" |
| explicitly_specified: false |
| nodep: false |
| } |
| attribute { |
| name: "includes" |
| type: STRING_LIST |
| string_list_value: "." |
| explicitly_specified: false |
| nodep: false |
| } |
| attribute { |
| name: "linkopts" |
| type: STRING_LIST |
| string_list_value: "-L/library/dir" |
| explicitly_specified: false |
| nodep: false |
| } |
| attribute { |
| name: "name" |
| type: STRING |
| string_value: "sum" |
| explicitly_specified: true |
| nodep: false |
| } |
| attribute { |
| name: "srcs" |
| type: LABEL_LIST |
| string_list_value: "//src/libs:sum.cpp" |
| explicitly_specified: true |
| nodep: false |
| } |
| attribute { |
| name: "hdrs" |
| type: LABEL_LIST |
| string_list_value: "//src/libs:sum.h" |
| explicitly_specified: true |
| nodep: false |
| } |
| attribute { |
| name: "visibility" |
| type: STRING_LIST |
| string_list_value: "//visibility:public" |
| explicitly_specified: true |
| nodep: true |
| } |
| } |
| }, |
| } |
| results { |
| target { |
| type: RULE |
| rule { |
| name: "//src/apps:hello" |
| rule_class: "cc_binary" |
| location: "/path/to/workspace/src/apps/BUILD.bazel:8:11" |
| attribute { |
| name: "copts" |
| type: STRING_LIST |
| string_list_value: "-O1" |
| explicitly_specified: true |
| nodep: false |
| } |
| attribute { |
| name: "defines" |
| type: STRING_LIST |
| string_list_value: "APPDEF" |
| explicitly_specified: false |
| nodep: false |
| } |
| attribute { |
| name: "linkopts" |
| type: STRING_LIST |
| string_list_value: "-L/app/dir" |
| explicitly_specified: false |
| nodep: false |
| } |
| attribute { |
| name: "name" |
| type: STRING |
| string_value: "hello" |
| explicitly_specified: true |
| nodep: false |
| } |
| attribute { |
| name: "srcs" |
| type: LABEL_LIST |
| string_list_value: "//src/apps:hello-world.cpp" |
| explicitly_specified: true |
| nodep: false |
| } |
| attribute { |
| name: "deps" |
| type: LABEL_LIST |
| string_list_value: "//src/libs:sum" |
| explicitly_specified: false |
| nodep: false |
| } |
| attribute { |
| name: "visibility" |
| type: STRING_LIST |
| string_list_value: "//visibility:public" |
| explicitly_specified: true |
| nodep: true |
| } |
| } |
| } |
| }` |
| |
| func TestExport_QueryReadError_ReturnsError(t *testing.T) { |
| fs := mocks.NewFileSystem(t) |
| e := NewCMakeExporter("projName", testWorkspaceDir, testCMakeOutFname, fs) |
| qcmd := mocks.NewQueryCommand(t) |
| qcmd.On("Read", mock.Anything).Return([]byte{}, skerr.Fmt("expected error")) |
| err := e.Export(qcmd) |
| assert.Error(t, err) |
| } |
| |
| func TestExport_InvalidProtobuf_ReturnsError(t *testing.T) { |
| fs := mocks.NewFileSystem(t) |
| e := NewCMakeExporter("projName", testWorkspaceDir, testCMakeOutFname, fs) |
| qcmd := mocks.NewQueryCommand(t) |
| qcmd.On("Read", mock.Anything).Return(make([]byte, 50), skerr.Fmt("empty data")) |
| err := e.Export(qcmd) |
| assert.Error(t, err) |
| } |
| |
| func TestExport_ValidProtobuf_Success(t *testing.T) { |
| protoData, err := textProtoToProtobuf(textProto) |
| require.NoError(t, err) |
| |
| var contents bytes.Buffer |
| fs := mocks.NewFileSystem(t) |
| fs.On("OpenFile", mock.Anything).Once().Run(func(args mock.Arguments) { |
| assert.True(t, filepath.IsAbs(args.String(0))) |
| assert.Equal(t, args.String(0), testCMakeOutFname) |
| }).Return(&contents, nil) |
| e := NewCMakeExporter("projName", testWorkspaceDir, testCMakeOutFname, fs) |
| qcmd := mocks.NewQueryCommand(t) |
| qcmd.On("Read", mock.Anything).Return(protoData, nil) |
| err = e.Export(qcmd) |
| require.NoError(t, err) |
| |
| // This expected CMake output text is created by hand. |
| const expected = `# DO NOT EDIT: This file is auto-generated. |
| cmake_minimum_required(VERSION 3.13) |
| |
| project(projName LANGUAGES C CXX) |
| |
| set(DEFAULT_COMPILE_FLAGS_MACOS "-std=c++17 -Wno-psabi --target=arm64-apple-macos11") |
| set(DEFAULT_COMPILE_FLAGS_LINUX "-std=c++17 -Wno-psabi -Wno-attributes") |
| |
| if (APPLE) |
| set(DEFAULT_COMPILE_FLAGS "${DEFAULT_COMPILE_FLAGS_MACOS}") |
| else() |
| set(DEFAULT_COMPILE_FLAGS "${DEFAULT_COMPILE_FLAGS_LINUX}") |
| endif() |
| |
| |
| # //src/apps:hello |
| add_executable(src_apps_hello "") |
| target_sources(src_apps_hello |
| PRIVATE |
| # Sources: |
| "${CMAKE_SOURCE_DIR}/src/apps/hello-world.cpp" |
| ) |
| set_target_properties(src_apps_hello PROPERTIES COMPILE_FLAGS |
| "${DEFAULT_COMPILE_FLAGS} -O1" |
| ) |
| set_target_properties(src_apps_hello PROPERTIES LINK_FLAGS |
| "-L/app/dir" |
| ) |
| set_target_properties(src_apps_hello PROPERTIES COMPILE_DEFINITIONS |
| "APPDEF;SUMDEF" |
| ) |
| set_target_properties(src_apps_hello PROPERTIES INCLUDE_DIRECTORIES |
| "${CMAKE_SOURCE_DIR}/src/libs;${CMAKE_SOURCE_DIR}" |
| ) |
| |
| # //src/libs:sum |
| add_library(src_libs_sum "") |
| target_sources(src_libs_sum |
| PRIVATE |
| # Sources: |
| "${CMAKE_SOURCE_DIR}/src/libs/sum.cpp" |
| # Headers: |
| "${CMAKE_SOURCE_DIR}/src/libs/sum.h" |
| ) |
| set_target_properties(src_libs_sum PROPERTIES COMPILE_FLAGS |
| "${DEFAULT_COMPILE_FLAGS} -O2" |
| ) |
| set_target_properties(src_libs_sum PROPERTIES LINK_FLAGS |
| "-L/library/dir" |
| ) |
| set_target_properties(src_libs_sum PROPERTIES COMPILE_DEFINITIONS |
| "SUMDEF" |
| ) |
| set_target_properties(src_libs_sum PROPERTIES INCLUDE_DIRECTORIES |
| "${CMAKE_SOURCE_DIR}/src/libs;${CMAKE_SOURCE_DIR}" |
| ) |
| ` |
| |
| assert.Equal(t, expected, contents.String()) |
| } |
| |
| func TestGetRuleCopts_CoptsExists_Success(t *testing.T) { |
| qr := analysis_v2.CqueryResult{} |
| err := prototext.Unmarshal([]byte(textProto), &qr) |
| require.NoError(t, err) |
| |
| r := findRule(&qr, "//src/apps:hello") |
| require.NotNil(t, r) |
| |
| copts, err := getRuleCopts(r) |
| require.NoError(t, err) |
| assert.Equal(t, []string{"${DEFAULT_COMPILE_FLAGS}", "-O1"}, copts) |
| } |