github.com/kubeshop/testkube@v1.17.23/pkg/tcl/expressionstcl/convert.go (about)

     1  // Copyright 2024 Testkube.
     2  //
     3  // Licensed as a Testkube Pro file under the Testkube Community
     4  // License (the "License"); you may not use this file except in compliance with
     5  // the License. You may obtain a copy of the License at
     6  //
     7  //     https://github.com/kubeshop/testkube/blob/main/licenses/TCL.txt
     8  
     9  package expressionstcl
    10  
    11  import (
    12  	"encoding/json"
    13  	"fmt"
    14  	"reflect"
    15  	"strconv"
    16  	"strings"
    17  )
    18  
    19  func toString(s interface{}) (string, error) {
    20  	// Fast track
    21  	v, ok := s.(string)
    22  	if ok {
    23  		return v, nil
    24  	}
    25  	if isNone(s) {
    26  		return "", nil
    27  	}
    28  	// Convert
    29  	if isNumber(s) {
    30  		return fmt.Sprintf("%v", s), nil
    31  	}
    32  	if isSlice(s) {
    33  		var err error
    34  		value := reflect.ValueOf(s)
    35  		results := make([]string, value.Len())
    36  		for i := 0; i < value.Len(); i++ {
    37  			results[i], err = toString(value.Index(i).Interface())
    38  			if err != nil {
    39  				err = fmt.Errorf("error while converting '%v' slice item: %v", value.Index(i), err)
    40  				return "", err
    41  			}
    42  		}
    43  		return strings.Join(results, ","), nil
    44  	}
    45  	b, err := json.Marshal(s)
    46  	if err != nil {
    47  		return "", fmt.Errorf("error while converting '%v' map to JSON: %v", s, err)
    48  	}
    49  	r := string(b)
    50  	if isMap(s) && r == "null" {
    51  		return "{}", nil
    52  	}
    53  	return r, nil
    54  }
    55  
    56  func toFloat(s interface{}) (float64, error) {
    57  	// Fast track
    58  	if v, ok := s.(float64); ok {
    59  		return v, nil
    60  	}
    61  	if isNone(s) {
    62  		return 0, nil
    63  	}
    64  	// Convert
    65  	str, err := toString(s)
    66  	if err != nil {
    67  		return 0, err
    68  	}
    69  	v, err := strconv.ParseFloat(str, 64)
    70  	if err != nil {
    71  		return 0, fmt.Errorf("error while converting value to number: %v: %v", s, err)
    72  	}
    73  	return v, nil
    74  }
    75  
    76  func toInt(s interface{}) (int64, error) {
    77  	// Fast track
    78  	if v, ok := s.(int64); ok {
    79  		return v, nil
    80  	}
    81  	if v, ok := s.(int); ok {
    82  		return int64(v), nil
    83  	}
    84  	if isNone(s) {
    85  		return 0, nil
    86  	}
    87  	// Convert
    88  	v, err := toFloat(s)
    89  	return int64(v), err
    90  }
    91  
    92  func toBool(s interface{}) (bool, error) {
    93  	// Fast track
    94  	if v, ok := s.(bool); ok {
    95  		return v, nil
    96  	}
    97  	if isNone(s) {
    98  		return false, nil
    99  	}
   100  	if isMap(s) || isSlice(s) {
   101  		return reflect.ValueOf(s).Len() > 0, nil
   102  	}
   103  	// Convert
   104  	value, err := toString(s)
   105  	if err != nil {
   106  		return false, fmt.Errorf("error while converting value to bool: %v: %v", value, err)
   107  	}
   108  	return !(value == "" || value == "false" || value == "0" || value == "off"), nil
   109  }
   110  
   111  func toMap(s interface{}) (map[string]interface{}, error) {
   112  	// Fast track
   113  	if v, ok := s.(map[string]interface{}); ok {
   114  		return v, nil
   115  	}
   116  	if isNone(s) {
   117  		return nil, nil
   118  	}
   119  	// Convert
   120  	if isStruct(s) {
   121  		v, err := json.Marshal(s)
   122  		if err != nil {
   123  			return nil, fmt.Errorf("error while marshaling value: %v: %v", s, err)
   124  		}
   125  		err = json.Unmarshal(v, &s)
   126  		if err != nil {
   127  			return nil, fmt.Errorf("error while unmarshaling value: %v: %v", s, err)
   128  		}
   129  	}
   130  	if isMap(s) {
   131  		value := reflect.ValueOf(s)
   132  		res := make(map[string]interface{}, value.Len())
   133  		for _, k := range value.MapKeys() {
   134  			kk, err := toString(k.Interface())
   135  			if err != nil {
   136  				return nil, fmt.Errorf("error while converting map key to string: %v: %v", k, err)
   137  			}
   138  			res[kk] = value.MapIndex(k).Interface()
   139  		}
   140  		return res, nil
   141  	}
   142  	if isSlice(s) {
   143  		value := reflect.ValueOf(s)
   144  		res := make(map[string]interface{}, value.Len())
   145  		for i := 0; i < value.Len(); i++ {
   146  			res[strconv.Itoa(i)] = value.Index(i).Interface()
   147  		}
   148  		return res, nil
   149  	}
   150  	return nil, fmt.Errorf("error while converting value to map: %v", s)
   151  }
   152  
   153  func toSlice(s interface{}) ([]interface{}, error) {
   154  	// Fast track
   155  	if v, ok := s.([]interface{}); ok {
   156  		return v, nil
   157  	}
   158  	if isNone(s) {
   159  		return nil, nil
   160  	}
   161  	// Convert
   162  	if isSlice(s) {
   163  		value := reflect.ValueOf(s)
   164  		res := make([]interface{}, value.Len())
   165  		for i := 0; i < value.Len(); i++ {
   166  			res[i] = value.Index(i).Interface()
   167  		}
   168  		return res, nil
   169  	}
   170  	if isMap(s) {
   171  		return nil, fmt.Errorf("error while converting map to slice: %v", s)
   172  	}
   173  	return nil, fmt.Errorf("error while converting value to slice: %v", s)
   174  }