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 }