| // Licensed to the Apache Software Foundation (ASF) under one or more | |
| // contributor license agreements. See the NOTICE file distributed with | |
| // this work for additional information regarding copyright ownership. | |
| // The ASF licenses this file to You under the Apache License, Version 2.0 | |
| // (the "License"); you may not use this file except in compliance with | |
| // the License. You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| package utils | |
| import ( | |
| "errors" | |
| "fmt" | |
| "github.com/google/uuid" | |
| "os" | |
| "path/filepath" | |
| "reflect" | |
| "regexp" | |
| "strings" | |
| "testing" | |
| ) | |
| const ( | |
| sourceDir = "sourceDir" | |
| fileName = "file.txt" | |
| fileContent = "content" | |
| testDataDir = "test_data" | |
| javaFileName = "JavaFileName.java" | |
| emptyFileName = "emptyFile.java" | |
| pythonExampleName = "wordcount.py" | |
| filePermission = 0600 | |
| fullPermission = 0755 | |
| ) | |
| func TestMain(m *testing.M) { | |
| err := setup() | |
| if err != nil { | |
| panic(fmt.Errorf("error during test setup: %s", err.Error())) | |
| } | |
| defer teardown() | |
| m.Run() | |
| } | |
| func setup() error { | |
| err := os.Mkdir(sourceDir, fullPermission) | |
| if err != nil { | |
| return err | |
| } | |
| filePath := filepath.Join(sourceDir, fileName) | |
| err = os.WriteFile(filePath, []byte(fileContent), filePermission) | |
| if err != nil { | |
| return err | |
| } | |
| sourceJavaFilePath := filepath.Join(testDataDir, javaFileName) | |
| javaFilePath := filepath.Join(sourceDir, javaFileName) | |
| err = CopyFile(sourceJavaFilePath, javaFilePath) | |
| if err != nil { | |
| return err | |
| } | |
| emptyFilePath := filepath.Join(sourceDir, emptyFileName) | |
| err = os.WriteFile(emptyFilePath, []byte(""), filePermission) | |
| if err != nil { | |
| return err | |
| } | |
| sourceWordCountPythonPath := filepath.Join(testDataDir, pythonExampleName) | |
| wordCountPythonPath := filepath.Join(sourceDir, pythonExampleName) | |
| err = CopyFile(sourceWordCountPythonPath, wordCountPythonPath) | |
| return err | |
| } | |
| func teardown() error { | |
| return os.RemoveAll(sourceDir) | |
| } | |
| func TestSpacesToEqualsOption(t *testing.T) { | |
| type args struct { | |
| pipelineOptions string | |
| } | |
| tests := []struct { | |
| name string | |
| args args | |
| want string | |
| }{ | |
| { | |
| name: "Args is empty string", | |
| args: args{pipelineOptions: ""}, | |
| want: "", | |
| }, | |
| { | |
| name: "Args with one option", | |
| args: args{pipelineOptions: "--opt1 valOpt"}, | |
| want: "--opt1=valOpt", | |
| }, | |
| { | |
| name: "Args with some options", | |
| args: args{pipelineOptions: "--opt1 valOpt --opt2 valOpt --opt3 valOpt"}, | |
| want: "--opt1=valOpt --opt2=valOpt --opt3=valOpt", | |
| }, | |
| } | |
| for _, tt := range tests { | |
| t.Run(tt.name, func(t *testing.T) { | |
| if got := ReplaceSpacesWithEquals(tt.args.pipelineOptions); got != tt.want { | |
| t.Errorf("ReplaceSpacesWithEquals() = %v, want %v", got, tt.want) | |
| } | |
| }) | |
| } | |
| } | |
| func TestInitVars(t *testing.T) { | |
| tests := []struct { | |
| name string | |
| want []interface{} | |
| }{ | |
| { | |
| name: "Create empty variables", | |
| want: []interface{}{EmptyLine, EmptyLine, errors.New(EmptyLine), false, RegularDefinition}, | |
| }, | |
| } | |
| for _, tt := range tests { | |
| t.Run(tt.name, func(t *testing.T) { | |
| got, got1, got2, got3, got4 := InitVars() | |
| variables := append([]interface{}{}, got, got1, got2, got3, got4) | |
| if !reflect.DeepEqual(variables, tt.want) { | |
| t.Errorf("InitVars() variables = %v, want %v", variables, tt.want) | |
| } | |
| }) | |
| } | |
| } | |
| func TestAddGraphToEndOfFile(t *testing.T) { | |
| txtFilePath := filepath.Join(sourceDir, fileName) | |
| txtFile, err := os.OpenFile(txtFilePath, os.O_APPEND|os.O_WRONLY, os.ModeAppend) | |
| if err != nil { | |
| panic(err) | |
| } | |
| defer txtFile.Close() | |
| incorrectFile, err := os.Open(txtFilePath) | |
| if err != nil { | |
| panic(err) | |
| } | |
| defer incorrectFile.Close() | |
| type args struct { | |
| spaces string | |
| err error | |
| tempFile *os.File | |
| pipelineName string | |
| } | |
| type fields struct { | |
| fileContent string | |
| filePath string | |
| } | |
| tests := []struct { | |
| name string | |
| args args | |
| fields fields | |
| wantErr bool | |
| }{ | |
| { | |
| name: "Add graph to the end of an existing file", | |
| args: args{ | |
| spaces: "", | |
| err: nil, | |
| tempFile: txtFile, | |
| pipelineName: uuid.New().String(), | |
| }, | |
| fields: fields{ | |
| fileContent: fileContent, | |
| filePath: txtFilePath, | |
| }, | |
| wantErr: false, | |
| }, | |
| { | |
| name: "Error during write data to file", | |
| args: args{ | |
| spaces: "", | |
| err: nil, | |
| tempFile: incorrectFile, | |
| pipelineName: uuid.New().String(), | |
| }, | |
| fields: fields{ | |
| fileContent: fileContent, | |
| filePath: txtFilePath, | |
| }, | |
| wantErr: true, | |
| }, | |
| } | |
| for _, tt := range tests { | |
| t.Run(tt.name, func(t *testing.T) { | |
| AddGraphToEndOfFile(tt.args.spaces, tt.args.err, tt.args.tempFile, tt.args.pipelineName) | |
| data, err := os.ReadFile(tt.fields.filePath) | |
| if err != nil { | |
| t.Errorf("AddGraphToEndOfFile() error during reading from a file = %v", err) | |
| } | |
| graphCode := fmt.Sprintf(pythonGraphCodePattern, tt.args.pipelineName, GraphFileName) | |
| graphCodeWithIndentation := strings.ReplaceAll(graphCode, indentationReplacement, tt.args.spaces) | |
| fileContentWithGraph := fileContent + "\n" + graphCodeWithIndentation | |
| if (string(data) != fileContentWithGraph) != tt.wantErr { | |
| t.Error("AddGraphToEndOfFile() wrong graph addition") | |
| } | |
| }) | |
| } | |
| } | |
| func TestGetPublicClassName(t *testing.T) { | |
| javaPublicClassNamePattern := "public class (.*?) [{|implements(.*)]" | |
| type args struct { | |
| filePath string | |
| pattern string | |
| } | |
| tests := []struct { | |
| name string | |
| args args | |
| want string | |
| wantErr bool | |
| }{ | |
| { | |
| name: "Get public class name from existing java file", | |
| args: args{ | |
| filePath: filepath.Join(sourceDir, javaFileName), | |
| pattern: javaPublicClassNamePattern, | |
| }, | |
| want: "MinimalWordCount", | |
| wantErr: false, | |
| }, | |
| { | |
| name: "Get public class name from empty file", | |
| args: args{ | |
| filePath: filepath.Join(sourceDir, emptyFileName), | |
| pattern: javaPublicClassNamePattern, | |
| }, | |
| want: "", | |
| wantErr: true, | |
| }, | |
| { | |
| name: "Get public class name from non-existent file", | |
| args: args{ | |
| filePath: filepath.Join(sourceDir, "file1.java"), | |
| pattern: javaPublicClassNamePattern, | |
| }, | |
| want: "", | |
| wantErr: true, | |
| }, | |
| } | |
| for _, tt := range tests { | |
| t.Run(tt.name, func(t *testing.T) { | |
| got, err := GetPublicClassName(tt.args.filePath, tt.args.pattern) | |
| if (err != nil) != tt.wantErr { | |
| t.Errorf("GetPublicClassName() error = %v, wantErr %v", err, tt.wantErr) | |
| return | |
| } | |
| if got != tt.want { | |
| t.Errorf("GetPublicClassName() got = %v, want %v", got, tt.want) | |
| } | |
| }) | |
| } | |
| } | |
| func TestAddNewLine(t *testing.T) { | |
| javaFile, err := os.OpenFile(filepath.Join(sourceDir, javaFileName), os.O_APPEND|os.O_WRONLY, os.ModeAppend) | |
| if err != nil { | |
| panic(err) | |
| } | |
| defer javaFile.Close() | |
| txtFile, err := os.Open(filepath.Join(sourceDir, fileName)) | |
| if err != nil { | |
| panic(err) | |
| } | |
| defer txtFile.Close() | |
| type args struct { | |
| newLine bool | |
| file *os.File | |
| } | |
| tests := []struct { | |
| name string | |
| args args | |
| wantErr bool | |
| }{ | |
| { | |
| name: "No line added to file", | |
| args: args{ | |
| newLine: false, | |
| file: nil, | |
| }, | |
| wantErr: false, | |
| }, | |
| { | |
| name: "Add a new line to an existing javaFile", | |
| args: args{ | |
| newLine: true, | |
| file: javaFile, | |
| }, | |
| wantErr: false, | |
| }, | |
| { | |
| name: "Error during write data to file", | |
| args: args{ | |
| newLine: true, | |
| file: txtFile, | |
| }, | |
| wantErr: true, | |
| }, | |
| } | |
| for _, tt := range tests { | |
| t.Run(tt.name, func(t *testing.T) { | |
| if err := AddNewLine(tt.args.newLine, tt.args.file); (err != nil) != tt.wantErr { | |
| t.Errorf("AddNewLine() error = %v, wantErr %v", err, tt.wantErr) | |
| } | |
| }) | |
| } | |
| } | |
| func TestProcessLine(t *testing.T) { | |
| pipelineName := uuid.New().String() | |
| pythonExample, err := os.OpenFile(filepath.Join(sourceDir, pythonExampleName), os.O_RDWR, fullPermission) | |
| if err != nil { | |
| panic(err) | |
| } | |
| defer pythonExample.Close() | |
| findPipelinePattern := `^(\s*)(.+) = beam.Pipeline` | |
| findWithPipelinePattern := `(\s*)with.+Pipeline.+as (.+):` | |
| emptyLine := EmptyLine | |
| type args struct { | |
| curLine string | |
| pipelineName *string | |
| spaces *string | |
| regs *[]*regexp.Regexp | |
| tempFile *os.File | |
| err error | |
| } | |
| tests := []struct { | |
| name string | |
| args args | |
| want bool | |
| wantDefType PipelineDefinitionType | |
| wantErr bool | |
| }{ | |
| { | |
| name: "Empty current line", | |
| args: args{ | |
| curLine: "", | |
| pipelineName: &pipelineName, | |
| spaces: &emptyLine, | |
| regs: &[]*regexp.Regexp{ | |
| regexp.MustCompile(findPipelinePattern), | |
| regexp.MustCompile(findWithPipelinePattern), | |
| }, | |
| tempFile: pythonExample, | |
| err: errors.New(EmptyLine), | |
| }, | |
| want: false, | |
| wantDefType: RegularDefinition, | |
| wantErr: false, | |
| }, | |
| { | |
| name: "With correct line", | |
| args: args{ | |
| curLine: "with beam.Pipeline(options=pipeline_options) as p:", | |
| pipelineName: &pipelineName, | |
| spaces: &emptyLine, | |
| regs: &[]*regexp.Regexp{ | |
| regexp.MustCompile(findPipelinePattern), | |
| regexp.MustCompile(findWithPipelinePattern), | |
| }, | |
| tempFile: pythonExample, | |
| err: errors.New(EmptyLine), | |
| }, | |
| want: true, | |
| wantDefType: RegularDefinition, | |
| wantErr: false, | |
| }, | |
| { | |
| name: "With empty pipelineId", | |
| args: args{ | |
| curLine: "with beam.Pipeline(options=pipeline_options) as p:", | |
| pipelineName: &emptyLine, | |
| spaces: &emptyLine, | |
| regs: &[]*regexp.Regexp{ | |
| regexp.MustCompile(findPipelinePattern), | |
| regexp.MustCompile(findWithPipelinePattern), | |
| }, | |
| tempFile: pythonExample, | |
| err: errors.New(EmptyLine), | |
| }, | |
| want: false, | |
| wantDefType: WithDefinition, | |
| wantErr: false, | |
| }, | |
| } | |
| for _, tt := range tests { | |
| t.Run(tt.name, func(t *testing.T) { | |
| got, gotDefType, err := ProcessLine(tt.args.curLine, tt.args.pipelineName, tt.args.spaces, tt.args.regs, tt.args.tempFile, tt.args.err) | |
| if (err != nil) != tt.wantErr { | |
| t.Errorf("ProcessLine() error = %v, wantErr %v", err, tt.wantErr) | |
| return | |
| } | |
| if got != tt.want { | |
| t.Errorf("ProcessLine() got = %v, want %v", got, tt.want) | |
| } | |
| if gotDefType != tt.wantDefType { | |
| t.Errorf("ProcessLine() gotDefType = %v, want %v", gotDefType, tt.wantDefType) | |
| } | |
| }) | |
| } | |
| } | |
| func TestRenameSourceCodeFile(t *testing.T) { | |
| type args struct { | |
| filePath string | |
| className string | |
| } | |
| tests := []struct { | |
| name string | |
| args args | |
| wantErr bool | |
| }{ | |
| { | |
| name: "Rename an existing file", | |
| args: args{ | |
| filePath: filepath.Join(sourceDir, fileName), | |
| className: "MOCK_CLASS_NAME", | |
| }, | |
| wantErr: false, | |
| }, | |
| { | |
| name: "Rename non-existent file", | |
| args: args{ | |
| filePath: filepath.Join(sourceDir, "file1.txt"), | |
| className: "MOCK_CLASS_NAME", | |
| }, | |
| wantErr: true, | |
| }, | |
| } | |
| for _, tt := range tests { | |
| t.Run(tt.name, func(t *testing.T) { | |
| if err := RenameSourceCodeFile(tt.args.filePath, tt.args.className); (err != nil) != tt.wantErr { | |
| t.Errorf("RenameSourceCodeFile() error = %v, wantErr %v", err, tt.wantErr) | |
| } | |
| }) | |
| } | |
| } |