github.com/drone/go-convert@v0.0.0-20240307072510-6bd371c65e61/convert/github/convert_test.go (about)

     1  // Copyright 2022 Harness, Inc.
     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 github
    16  
    17  import (
    18  	"fmt"
    19  	"io/ioutil"
    20  	"path/filepath"
    21  	"sort"
    22  	"testing"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  	"gopkg.in/yaml.v3"
    26  )
    27  
    28  func TestConvert(t *testing.T) {
    29  	tests, err := filepath.Glob("testdata/*/*.yaml")
    30  	if err != nil {
    31  		t.Error(err)
    32  		return
    33  	}
    34  
    35  	for _, test := range tests {
    36  		t.Run(test, func(t *testing.T) {
    37  			// convert the yaml file from github to harness
    38  			converter := New()
    39  			tmp1, err := converter.ConvertFile(test)
    40  			if err != nil {
    41  				t.Error(err)
    42  				return
    43  			}
    44  
    45  			// unmarshal the converted yaml file to a map
    46  			got := map[string]interface{}{}
    47  			if err := yaml.Unmarshal(tmp1, &got); err != nil {
    48  				t.Error(err)
    49  				return
    50  			}
    51  
    52  			got = normalizeMap(got)
    53  
    54  			// parse the golden yaml file
    55  			data, err := ioutil.ReadFile(test + ".golden")
    56  			if err != nil {
    57  				t.Error(err)
    58  				return
    59  			}
    60  
    61  			// unmarshal the golden yaml file to a map
    62  			want := map[string]interface{}{}
    63  			if err := yaml.Unmarshal(data, &want); err != nil {
    64  				t.Error(err)
    65  				return
    66  			}
    67  
    68  			want = normalizeMap(want)
    69  
    70  			// compare the converted yaml to the golden file
    71  			if diff := cmp.Diff(got, want); diff != "" {
    72  				t.Errorf("Unexpected conversion result")
    73  				t.Log(diff)
    74  			}
    75  		})
    76  	}
    77  }
    78  
    79  func normalizeMap(m map[string]interface{}) map[string]interface{} {
    80  	normalized := make(map[string]interface{}, len(m))
    81  	keys := make([]string, 0, len(m))
    82  
    83  	for k := range m {
    84  		keys = append(keys, k)
    85  	}
    86  	sort.Strings(keys)
    87  
    88  	for _, k := range keys {
    89  		v := m[k]
    90  		switch t := v.(type) {
    91  		case map[string]interface{}:
    92  			normalized[k] = normalizeMap(t)
    93  		case map[interface{}]interface{}:
    94  			normalizedMap := make(map[string]interface{}, len(t))
    95  			for k, v := range t {
    96  				normalizedMap[fmt.Sprintf("%v", k)] = v
    97  			}
    98  			normalized[k] = normalizeMap(normalizedMap)
    99  		case []interface{}:
   100  			normalized[k] = normalizeSlice(t)
   101  		default:
   102  			normalized[k] = v
   103  		}
   104  	}
   105  
   106  	return normalized
   107  }
   108  
   109  func normalizeSlice(s []interface{}) []interface{} {
   110  	for i, v := range s {
   111  		if m, ok := v.(map[string]interface{}); ok {
   112  			s[i] = normalizeMap(m)
   113  		}
   114  	}
   115  	sort.SliceStable(s, func(i, j int) bool {
   116  		mi, oki := s[i].(map[string]interface{})
   117  		mj, okj := s[j].(map[string]interface{})
   118  		if !oki || !okj {
   119  			// At least one of the values is not a map, so don't attempt to sort
   120  			return false
   121  		}
   122  		ni, inj := mi["name"].(string)
   123  		nj, inj := mj["name"].(string)
   124  		if inj {
   125  			// Both maps have a string name field, so sort by these
   126  			return ni < nj
   127  		}
   128  		// At least one map doesn't have a string name field, so don't attempt to sort
   129  		return false
   130  	})
   131  	return s
   132  }