github.com/distbuild/reclient@v0.0.0-20240401075343-3de72e395564/internal/pkg/inputprocessor/action/nacl/preprocessor_test.go (about)

     1  // Copyright 2023 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package nacl
    16  
    17  import (
    18  	"context"
    19  	"os"
    20  	"regexp"
    21  	"testing"
    22  
    23  	spb "github.com/bazelbuild/reclient/api/scandeps"
    24  	"github.com/bazelbuild/reclient/internal/pkg/inputprocessor"
    25  	"github.com/bazelbuild/reclient/internal/pkg/inputprocessor/action/cppcompile"
    26  )
    27  
    28  func TestComputeSpec(t *testing.T) {
    29  	tests := []struct {
    30  		name          string
    31  		execPath      string
    32  		extraArgs     []string
    33  		wantFlagRegex string
    34  		wantErr       bool
    35  	}{
    36  		{
    37  			name:          "nacl toolchain x86_64",
    38  			execPath:      "fake/native_client/toolchain/mac_x86/x86_64-nacl-clang",
    39  			wantFlagRegex: "--target=x86_64-nacl",
    40  		},
    41  		{
    42  			name:          "nacl toolchain mipsel",
    43  			execPath:      "native_client/toolchain/foo/bar/fake_os/mipsel-nacl-clang",
    44  			wantFlagRegex: "--target=mipsel-nacl",
    45  		},
    46  		{
    47  			name:          "nacl toolchain pnacl",
    48  			execPath:      "native_client/toolchain/pnacl-clang",
    49  			extraArgs:     []string{"-pnacl=foo", "--pnacl=bar"},
    50  			wantFlagRegex: "--target=i686-nacl",
    51  		},
    52  		{
    53  			name:          "nacl toolchain pnacl, already has target",
    54  			execPath:      "native_client/toolchain/pnacl",
    55  			extraArgs:     []string{"-target", "i686-nacl"},
    56  			wantFlagRegex: "-target",
    57  		},
    58  		{
    59  			name:     "no nacl toolchain, failure",
    60  			execPath: "clang",
    61  			wantErr:  true,
    62  		},
    63  	}
    64  
    65  	for _, tc := range tests {
    66  		t.Run(tc.name, func(t *testing.T) {
    67  			ctx := context.Background()
    68  			s := &stubCPPDepScanner{
    69  				res: []string{"foo.h"},
    70  				err: nil,
    71  			}
    72  			cc := &cppcompile.Preprocessor{
    73  				CPPDepScanner:    s,
    74  				BasePreprocessor: &inputprocessor.BasePreprocessor{Ctx: ctx},
    75  			}
    76  			c := &Preprocessor{cc}
    77  
    78  			pwd, err := os.Getwd()
    79  			if err != nil {
    80  				t.Fatalf("Unable to get current working directory: %v", err)
    81  			}
    82  			cc.Options = inputprocessor.Options{
    83  				ExecRoot: pwd,
    84  				Cmd:      []string{tc.execPath, "-o", "foo.o", "foo.cpp"},
    85  			}
    86  			cc.Options.Cmd = append(cc.Options.Cmd, tc.extraArgs...)
    87  
    88  			err = c.ParseFlags()
    89  			if !tc.wantErr && err != nil {
    90  				t.Fatalf("ParseFlags() failed: %v", err)
    91  			}
    92  			err = c.ComputeSpec()
    93  			if !tc.wantErr && err != nil {
    94  				t.Fatalf("ComputeSpec() failed: %v", err)
    95  			} else if tc.wantErr && err == nil {
    96  				t.Fatalf("ComputeSpec() did not fail: %v", err)
    97  			}
    98  			if containsRegexCount(s.gotCmd, "-pnacl") > 0 {
    99  				t.Errorf("ComputeSpec() must remove '-pnacl' flag when calling clang-scan-deps for nacl toolchain: %v", s.gotCmd)
   100  			}
   101  			if tc.wantFlagRegex != "" && containsRegexCount(s.gotCmd, tc.wantFlagRegex) != 1 {
   102  				t.Errorf("ComputeSpec() must append %s when calling clang-scan-deps for nacl toolchains: %v", tc.wantFlagRegex, s.gotCmd)
   103  			} else if tc.wantFlagRegex == "" && containsRegexCount(s.gotCmd, "-target") > 0 {
   104  				t.Errorf("ComputeSpec() must _not_ append %s when calling clang-scan-deps for non nacl toolchains: %v", tc.wantFlagRegex, s.gotCmd)
   105  			}
   106  		})
   107  	}
   108  }
   109  
   110  type stubCPPDepScanner struct {
   111  	gotCmd       []string
   112  	gotFileName  string
   113  	gotDirectory string
   114  
   115  	res []string
   116  	err error
   117  }
   118  
   119  func (s *stubCPPDepScanner) ProcessInputs(_ context.Context, _ string, command []string, filename, directory string, _ []string) ([]string, bool, error) {
   120  	s.gotCmd = command
   121  	s.gotFileName = filename
   122  	s.gotDirectory = directory
   123  
   124  	return s.res, false, s.err
   125  }
   126  
   127  func (s *stubCPPDepScanner) Capabilities() *spb.CapabilitiesResponse {
   128  	return nil
   129  }
   130  
   131  func containsRegexCount(src []string, pattern string) int {
   132  	total := 0
   133  	for _, v := range src {
   134  		if ok, err := regexp.Match(pattern, []byte(v)); err == nil && ok {
   135  			total = total + 1
   136  		}
   137  	}
   138  	return total
   139  }