URI: 
       checkers.go - hugo - [fork] hugo port for 9front
  HTML git clone https://git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
       checkers.go (4574B)
       ---
            1 // Copyright 2019 The Hugo Authors. All rights reserved.
            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 // http://www.apache.org/licenses/LICENSE-2.0
            7 //
            8 // Unless required by applicable law or agreed to in writing, software
            9 // distributed under the License is distributed on an "AS IS" BASIS,
           10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
           11 // See the License for the specific language governing permissions and
           12 // limitations under the License.
           13 
           14 package hqt
           15 
           16 import (
           17         "errors"
           18         "fmt"
           19         "math"
           20         "reflect"
           21         "strings"
           22 
           23         qt "github.com/frankban/quicktest"
           24         "github.com/gohugoio/hugo/htesting"
           25         "github.com/google/go-cmp/cmp"
           26         "github.com/spf13/cast"
           27 )
           28 
           29 // IsSameString asserts that two strings are equal. The two strings
           30 // are normalized (whitespace removed) before doing a ==.
           31 // Also note that two strings can be the same even if they're of different
           32 // types.
           33 var IsSameString qt.Checker = &stringChecker{
           34         argNames: []string{"got", "want"},
           35 }
           36 
           37 // IsSameType asserts that got is the same type as want.
           38 var IsSameType qt.Checker = &typeChecker{
           39         argNames: []string{"got", "want"},
           40 }
           41 
           42 // IsSameFloat64 asserts that two float64 values are equal within a small delta.
           43 var IsSameFloat64 = qt.CmpEquals(cmp.Comparer(func(a, b float64) bool {
           44         return math.Abs(a-b) < 0.0001
           45 }))
           46 
           47 type argNames []string
           48 
           49 func (a argNames) ArgNames() []string {
           50         return a
           51 }
           52 
           53 type typeChecker struct {
           54         argNames
           55 }
           56 
           57 // Check implements Checker.Check by checking that got and args[0] is of the same type.
           58 func (c *typeChecker) Check(got any, args []any, note func(key string, value any)) (err error) {
           59         if want := args[0]; reflect.TypeOf(got) != reflect.TypeOf(want) {
           60                 if _, ok := got.(error); ok && want == nil {
           61                         return errors.New("got non-nil error")
           62                 }
           63                 return errors.New("values are not of same type")
           64         }
           65         return nil
           66 }
           67 
           68 type stringChecker struct {
           69         argNames
           70 }
           71 
           72 // Check implements Checker.Check by checking that got and args[0] represents the same normalized text (whitespace etc. removed).
           73 func (c *stringChecker) Check(got any, args []any, note func(key string, value any)) (err error) {
           74         s1, s2 := cast.ToString(got), cast.ToString(args[0])
           75 
           76         if s1 == s2 {
           77                 return nil
           78         }
           79 
           80         s1, s2 = normalizeString(s1), normalizeString(s2)
           81 
           82         if s1 == s2 {
           83                 return nil
           84         }
           85 
           86         return fmt.Errorf("values are not the same text: %s", strings.Join(htesting.DiffStrings(s1, s2), " | "))
           87 }
           88 
           89 func normalizeString(s string) string {
           90         s = strings.ReplaceAll(s, "\r\n", "\n")
           91 
           92         lines := strings.Split(strings.TrimSpace(s), "\n")
           93         for i, line := range lines {
           94                 lines[i] = strings.Join(strings.Fields(strings.TrimSpace(line)), "")
           95         }
           96         return strings.Join(lines, "\n")
           97 }
           98 
           99 // IsAllElementsEqual asserts that all elements in the slice are equal.
          100 var IsAllElementsEqual qt.Checker = &sliceAllElementsEqualChecker{
          101         argNames: []string{"got"},
          102 }
          103 
          104 type sliceAllElementsEqualChecker struct {
          105         argNames
          106 }
          107 
          108 func (c *sliceAllElementsEqualChecker) Check(got any, args []any, note func(key string, value any)) (err error) {
          109         gotSlice := reflect.ValueOf(got)
          110         numElements := gotSlice.Len()
          111         if numElements < 2 {
          112                 return nil
          113         }
          114         first := gotSlice.Index(0).Interface()
          115         // Check that the others are equal to the first.
          116         for i := 1; i < numElements; i++ {
          117                 if diff := cmp.Diff(first, gotSlice.Index(i).Interface()); diff != "" {
          118                         return fmt.Errorf("element %d is not equal to the first element:\n%s", i, diff)
          119                 }
          120         }
          121 
          122         return nil
          123 }
          124 
          125 // DeepAllowUnexported creates an option to allow compare of unexported types
          126 // in the given list of types.
          127 // see https://github.com/google/go-cmp/issues/40#issuecomment-328615283
          128 func DeepAllowUnexported(vs ...any) cmp.Option {
          129         m := make(map[reflect.Type]struct{})
          130         for _, v := range vs {
          131                 structTypes(reflect.ValueOf(v), m)
          132         }
          133         var typs []any
          134         for t := range m {
          135                 typs = append(typs, reflect.New(t).Elem().Interface())
          136         }
          137         return cmp.AllowUnexported(typs...)
          138 }
          139 
          140 func structTypes(v reflect.Value, m map[reflect.Type]struct{}) {
          141         if !v.IsValid() {
          142                 return
          143         }
          144         switch v.Kind() {
          145         case reflect.Ptr:
          146                 if !v.IsNil() {
          147                         structTypes(v.Elem(), m)
          148                 }
          149         case reflect.Interface:
          150                 if !v.IsNil() {
          151                         structTypes(v.Elem(), m)
          152                 }
          153         case reflect.Slice, reflect.Array:
          154                 for i := range v.Len() {
          155                         structTypes(v.Index(i), m)
          156                 }
          157         case reflect.Map:
          158                 for _, k := range v.MapKeys() {
          159                         structTypes(v.MapIndex(k), m)
          160                 }
          161         case reflect.Struct:
          162                 m[v.Type()] = struct{}{}
          163                 for i := range v.NumField() {
          164                         structTypes(v.Field(i), m)
          165                 }
          166         }
          167 }