github.com/weaviate/weaviate@v1.24.6/test/acceptance/graphql_resolvers/aggregate_response_assert.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package test
    13  
    14  import (
    15  	"encoding/json"
    16  	"fmt"
    17  	"testing"
    18  
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/weaviate/weaviate/entities/schema"
    21  )
    22  
    23  const delta = 0.00001
    24  
    25  type assertFunc func(response map[string]interface{}) bool
    26  
    27  type aggregateResponseAssert struct {
    28  	t      *testing.T
    29  	assert *assert.Assertions
    30  }
    31  
    32  func newAggregateResponseAssert(t *testing.T) *aggregateResponseAssert {
    33  	return &aggregateResponseAssert{t, assert.New(t)}
    34  }
    35  
    36  func (a *aggregateResponseAssert) meta(count int64) assertFunc {
    37  	return func(response map[string]interface{}) bool {
    38  		metaKey := "meta"
    39  		if !a.assert.Contains(response, metaKey) {
    40  			return false
    41  		}
    42  		return a.hasInt(response[metaKey].(map[string]interface{}), metaKey, "count", count)
    43  	}
    44  }
    45  
    46  func (a *aggregateResponseAssert) groupedBy(value string, path ...interface{}) assertFunc {
    47  	return func(response map[string]interface{}) bool {
    48  		groupedByKey := "groupedBy"
    49  		if !a.assert.Contains(response, groupedByKey) {
    50  			return false
    51  		}
    52  		aggMap := response[groupedByKey].(map[string]interface{})
    53  		return combinedAssert(
    54  			a.hasString(aggMap, groupedByKey, "value", value),
    55  			a.hasArray(aggMap, groupedByKey, "path", path),
    56  		)
    57  	}
    58  }
    59  
    60  func (a *aggregateResponseAssert) pointingTo(propName string, path ...interface{}) assertFunc {
    61  	return func(response map[string]interface{}) bool {
    62  		if !a.assert.Contains(response, propName) {
    63  			return false
    64  		}
    65  		aggMap := response[propName].(map[string]interface{})
    66  		return a.hasArray(aggMap, propName, "pointingTo", path)
    67  	}
    68  }
    69  
    70  func (a *aggregateResponseAssert) typedBoolean(dataType schema.DataType, propName string,
    71  	count, totalFalse, totalTrue int64,
    72  	percentageFalse, percentageTrue float64,
    73  ) assertFunc {
    74  	return func(response map[string]interface{}) bool {
    75  		if !a.assert.Contains(response, propName) {
    76  			return false
    77  		}
    78  		aggMap := response[propName].(map[string]interface{})
    79  		return combinedAssert(
    80  			a.hasInt(aggMap, propName, "count", count),
    81  			a.hasInt(aggMap, propName, "totalFalse", totalFalse),
    82  			a.hasInt(aggMap, propName, "totalTrue", totalTrue),
    83  			a.hasNumber(aggMap, propName, "percentageFalse", percentageFalse),
    84  			a.hasNumber(aggMap, propName, "percentageTrue", percentageTrue),
    85  			a.hasString(aggMap, propName, "type", string(dataType)),
    86  		)
    87  	}
    88  }
    89  
    90  func (a *aggregateResponseAssert) booleanArray(propName string,
    91  	count, totalFalse, totalTrue int64,
    92  	percentageFalse, percentageTrue float64,
    93  ) assertFunc {
    94  	return a.typedBoolean(schema.DataTypeBooleanArray, propName, count, totalFalse, totalTrue,
    95  		percentageFalse, percentageTrue)
    96  }
    97  
    98  func (a *aggregateResponseAssert) boolean(propName string,
    99  	count, totalFalse, totalTrue int64,
   100  	percentageFalse, percentageTrue float64,
   101  ) assertFunc {
   102  	return a.typedBoolean(schema.DataTypeBoolean, propName, count, totalFalse, totalTrue,
   103  		percentageFalse, percentageTrue)
   104  }
   105  
   106  func (a *aggregateResponseAssert) typedBoolean0(dataType schema.DataType, propName string) assertFunc {
   107  	return func(response map[string]interface{}) bool {
   108  		if !a.assert.Contains(response, propName) {
   109  			return false
   110  		}
   111  		aggMap := response[propName].(map[string]interface{})
   112  		return combinedAssert(
   113  			a.hasInt(aggMap, propName, "count", 0),
   114  			a.hasInt(aggMap, propName, "totalFalse", 0),
   115  			a.hasInt(aggMap, propName, "totalTrue", 0),
   116  			a.hasNil(aggMap, propName, "percentageFalse"),
   117  			a.hasNil(aggMap, propName, "percentageTrue"),
   118  			a.hasString(aggMap, propName, "type", string(dataType)),
   119  		)
   120  	}
   121  }
   122  
   123  func (a *aggregateResponseAssert) booleanArray0(propName string) assertFunc {
   124  	return a.typedBoolean0(schema.DataTypeBooleanArray, propName)
   125  }
   126  
   127  func (a *aggregateResponseAssert) boolean0(propName string) assertFunc {
   128  	return a.typedBoolean0(schema.DataTypeBoolean, propName)
   129  }
   130  
   131  func (a *aggregateResponseAssert) typedInts(dataType schema.DataType, propName string,
   132  	count, maximum, minimum, mode, sum int64,
   133  	median, mean float64,
   134  ) assertFunc {
   135  	return func(response map[string]interface{}) bool {
   136  		if !a.assert.Contains(response, propName) {
   137  			return false
   138  		}
   139  		aggMap := response[propName].(map[string]interface{})
   140  		return combinedAssert(
   141  			a.hasInt(aggMap, propName, "count", count),
   142  			a.hasInt(aggMap, propName, "maximum", maximum),
   143  			a.hasInt(aggMap, propName, "minimum", minimum),
   144  			a.hasInt(aggMap, propName, "mode", mode),
   145  			a.hasInt(aggMap, propName, "sum", sum),
   146  			a.hasNumber(aggMap, propName, "median", median),
   147  			a.hasNumber(aggMap, propName, "mean", mean),
   148  			a.hasString(aggMap, propName, "type", string(dataType)),
   149  		)
   150  	}
   151  }
   152  
   153  func (a *aggregateResponseAssert) intArray(propName string,
   154  	count, maximum, minimum, mode, sum int64,
   155  	median, mean float64,
   156  ) assertFunc {
   157  	return a.typedInts(schema.DataTypeIntArray, propName, count, maximum, minimum,
   158  		mode, sum, median, mean)
   159  }
   160  
   161  func (a *aggregateResponseAssert) int(propName string,
   162  	count, maximum, minimum, mode, sum int64,
   163  	median, mean float64,
   164  ) assertFunc {
   165  	return a.typedInts(schema.DataTypeInt, propName, count, maximum, minimum,
   166  		mode, sum, median, mean)
   167  }
   168  
   169  func (a *aggregateResponseAssert) typedInts0(dataType schema.DataType, propName string) assertFunc {
   170  	return func(response map[string]interface{}) bool {
   171  		if !a.assert.Contains(response, propName) {
   172  			return false
   173  		}
   174  		aggMap := response[propName].(map[string]interface{})
   175  		return combinedAssert(
   176  			a.hasInt(aggMap, propName, "count", 0),
   177  			a.hasNil(aggMap, propName, "maximum"),
   178  			a.hasNil(aggMap, propName, "minimum"),
   179  			a.hasNil(aggMap, propName, "mode"),
   180  			a.hasNil(aggMap, propName, "sum"),
   181  			a.hasNil(aggMap, propName, "median"),
   182  			a.hasNil(aggMap, propName, "mean"),
   183  			a.hasString(aggMap, propName, "type", string(dataType)),
   184  		)
   185  	}
   186  }
   187  
   188  func (a *aggregateResponseAssert) intArray0(propName string) assertFunc {
   189  	return a.typedInts0(schema.DataTypeIntArray, propName)
   190  }
   191  
   192  func (a *aggregateResponseAssert) int0(propName string) assertFunc {
   193  	return a.typedInts0(schema.DataTypeInt, propName)
   194  }
   195  
   196  func (a *aggregateResponseAssert) typedNumbers(dataType schema.DataType, propName string,
   197  	count int64,
   198  	maximum, minimum, mode, sum, median, mean float64,
   199  ) assertFunc {
   200  	return func(response map[string]interface{}) bool {
   201  		if !a.assert.Contains(response, propName) {
   202  			return false
   203  		}
   204  		aggMap := response[propName].(map[string]interface{})
   205  		return combinedAssert(
   206  			a.hasInt(aggMap, propName, "count", count),
   207  			a.hasNumber(aggMap, propName, "maximum", maximum),
   208  			a.hasNumber(aggMap, propName, "minimum", minimum),
   209  			a.hasNumber(aggMap, propName, "mode", mode),
   210  			a.hasNumber(aggMap, propName, "sum", sum),
   211  			a.hasNumber(aggMap, propName, "median", median),
   212  			a.hasNumber(aggMap, propName, "mean", mean),
   213  			a.hasString(aggMap, propName, "type", string(dataType)),
   214  		)
   215  	}
   216  }
   217  
   218  func (a *aggregateResponseAssert) numberArray(propName string,
   219  	count int64,
   220  	maximum, minimum, mode, sum, median, mean float64,
   221  ) assertFunc {
   222  	return a.typedNumbers(schema.DataTypeNumberArray, propName, count, maximum, minimum,
   223  		mode, sum, median, mean)
   224  }
   225  
   226  func (a *aggregateResponseAssert) number(propName string,
   227  	count int64,
   228  	maximum, minimum, mode, sum, median, mean float64,
   229  ) assertFunc {
   230  	return a.typedNumbers(schema.DataTypeNumber, propName, count, maximum, minimum,
   231  		mode, sum, median, mean)
   232  }
   233  
   234  func (a *aggregateResponseAssert) typedNumbers0(dataType schema.DataType, propName string) assertFunc {
   235  	return func(response map[string]interface{}) bool {
   236  		if !a.assert.Contains(response, propName) {
   237  			return false
   238  		}
   239  		aggMap := response[propName].(map[string]interface{})
   240  		return combinedAssert(
   241  			a.hasInt(aggMap, propName, "count", 0),
   242  			a.hasNil(aggMap, propName, "maximum"),
   243  			a.hasNil(aggMap, propName, "minimum"),
   244  			a.hasNil(aggMap, propName, "mode"),
   245  			a.hasNil(aggMap, propName, "sum"),
   246  			a.hasNil(aggMap, propName, "median"),
   247  			a.hasNil(aggMap, propName, "mean"),
   248  			a.hasString(aggMap, propName, "type", string(dataType)),
   249  		)
   250  	}
   251  }
   252  
   253  func (a *aggregateResponseAssert) numberArray0(propName string) assertFunc {
   254  	return a.typedNumbers0(schema.DataTypeNumberArray, propName)
   255  }
   256  
   257  func (a *aggregateResponseAssert) number0(propName string) assertFunc {
   258  	return a.typedNumbers0(schema.DataTypeNumber, propName)
   259  }
   260  
   261  func (a *aggregateResponseAssert) dateArray(propName string, count int64) assertFunc {
   262  	return a.date(propName, count)
   263  }
   264  
   265  func (a *aggregateResponseAssert) date(propName string, count int64) assertFunc {
   266  	return func(response map[string]interface{}) bool {
   267  		if !a.assert.Contains(response, propName) {
   268  			return false
   269  		}
   270  		return a.hasInt(response[propName].(map[string]interface{}), propName, "count", count)
   271  	}
   272  }
   273  
   274  func (a *aggregateResponseAssert) dateArray0(propName string) assertFunc {
   275  	return a.date(propName, 0)
   276  }
   277  
   278  func (a *aggregateResponseAssert) date0(propName string) assertFunc {
   279  	return a.date(propName, 0)
   280  }
   281  
   282  func (a *aggregateResponseAssert) typedStrings(dataType schema.DataType, propName string,
   283  	count int64,
   284  	values []string, occurrences []int64,
   285  ) assertFunc {
   286  	return func(response map[string]interface{}) bool {
   287  		if !a.assert.Contains(response, propName) {
   288  			return false
   289  		}
   290  		aggMap := response[propName].(map[string]interface{})
   291  		return combinedAssert(
   292  			a.hasInt(aggMap, propName, "count", count),
   293  			a.hasString(aggMap, propName, "type", string(dataType)),
   294  			a.hasOccurrences(aggMap, propName, values, occurrences),
   295  		)
   296  	}
   297  }
   298  
   299  func (a *aggregateResponseAssert) typedStrings0(dataType schema.DataType, propName string) assertFunc {
   300  	return func(response map[string]interface{}) bool {
   301  		if !a.assert.Contains(response, propName) {
   302  			return false
   303  		}
   304  		aggMap := response[propName].(map[string]interface{})
   305  		return combinedAssert(
   306  			a.hasInt(aggMap, propName, "count", 0),
   307  			a.hasString(aggMap, propName, "type", string(dataType)),
   308  			a.hasOccurrences(aggMap, propName, nil, nil),
   309  		)
   310  	}
   311  }
   312  
   313  func (a *aggregateResponseAssert) textArray(propName string,
   314  	count int64,
   315  	values []string, occurrences []int64,
   316  ) assertFunc {
   317  	return a.typedStrings(schema.DataTypeTextArray, propName, count, values, occurrences)
   318  }
   319  
   320  func (a *aggregateResponseAssert) text(propName string,
   321  	count int64,
   322  	values []string, occurrences []int64,
   323  ) assertFunc {
   324  	return a.typedStrings(schema.DataTypeText, propName, count, values, occurrences)
   325  }
   326  
   327  func (a *aggregateResponseAssert) textArray0(propName string) assertFunc {
   328  	return a.typedStrings0(schema.DataTypeTextArray, propName)
   329  }
   330  
   331  func (a *aggregateResponseAssert) text0(propName string) assertFunc {
   332  	return a.typedStrings0(schema.DataTypeText, propName)
   333  }
   334  
   335  func (a *aggregateResponseAssert) hasOccurrences(parentMap map[string]interface{},
   336  	parentKey string, values []string, occurrences []int64,
   337  ) bool {
   338  	key := "topOccurrences"
   339  	to, exists := parentMap[key]
   340  	if !exists {
   341  		return a.assert.Fail(fmt.Sprintf("'%s' does not have '%s'\n%#v", parentKey, key, parentMap))
   342  	}
   343  
   344  	toArr := to.([]interface{})
   345  	assertResults := make([]bool, len(values))
   346  	for i := range values {
   347  		key := fmt.Sprintf("%s.%s[%d]", parentKey, key, i)
   348  		toSingle := toArr[i].(map[string]interface{})
   349  		assertResults[i] = combinedAssert(
   350  			a.hasString(toSingle, key, "value", values[i]),
   351  			a.hasInt(toSingle, key, "occurs", occurrences[i]),
   352  		)
   353  	}
   354  	return combinedAssert(assertResults...)
   355  }
   356  
   357  func (a *aggregateResponseAssert) hasNumber(parentMap map[string]interface{},
   358  	parentKey, key string, expectedValue float64,
   359  ) bool {
   360  	v, exist := parentMap[key]
   361  	if !exist {
   362  		return a.assert.Fail(fmt.Sprintf("'%s' does not have '%s'\n%#v", parentKey, key, parentMap))
   363  	}
   364  	if v == nil {
   365  		return a.assert.Fail(fmt.Sprintf("'%s.%s' is nil", parentKey, key))
   366  	}
   367  	if v, ok := v.(json.Number); ok {
   368  		if value, err := v.Float64(); err == nil {
   369  			if a.assert.InDelta(expectedValue, value, delta) {
   370  				return true
   371  			}
   372  			return a.assert.Fail(fmt.Sprintf("'%s.%s' of %#v is not equal to %#v", parentKey, key, value, expectedValue))
   373  		}
   374  	}
   375  	return a.assert.Fail(fmt.Sprintf("'%s.%s' of %#v is not equal to %#v", parentKey, key, v, expectedValue))
   376  }
   377  
   378  func (a *aggregateResponseAssert) hasInt(parentMap map[string]interface{},
   379  	parentKey, key string, expectedValue int64,
   380  ) bool {
   381  	v, exist := parentMap[key]
   382  	if !exist {
   383  		return a.assert.Fail(fmt.Sprintf("'%s' does not have '%s'\n%#v", parentKey, key, parentMap))
   384  	}
   385  	if v == nil {
   386  		return a.assert.Fail(fmt.Sprintf("'%s.%s' is nil", parentKey, key))
   387  	}
   388  	if v, ok := v.(json.Number); ok {
   389  		if value, err := v.Int64(); err == nil {
   390  			if value == expectedValue {
   391  				return true
   392  			}
   393  			return a.assert.Fail(fmt.Sprintf("'%s.%s' of %#v is not equal to %#v", parentKey, key, value, expectedValue))
   394  		}
   395  	}
   396  	return a.assert.Fail(fmt.Sprintf("'%s.%s' of %#v is not equal to %#v", parentKey, key, v, expectedValue))
   397  }
   398  
   399  func (a *aggregateResponseAssert) hasString(parentMap map[string]interface{},
   400  	parentKey, key string, expectedValue string,
   401  ) bool {
   402  	v, exist := parentMap[key]
   403  	if !exist {
   404  		return a.assert.Fail(fmt.Sprintf("'%s' does not have '%s'\n%#v", parentKey, key, parentMap))
   405  	}
   406  	if v == nil {
   407  		return a.assert.Fail(fmt.Sprintf("'%s.%s' is nil", parentKey, key))
   408  	}
   409  	if v != expectedValue {
   410  		return a.assert.Fail(fmt.Sprintf("'%s.%s' of %#v is not equal to %#v", parentKey, key, v, expectedValue))
   411  	}
   412  	return true
   413  }
   414  
   415  func (a *aggregateResponseAssert) hasNil(parentMap map[string]interface{},
   416  	parentKey, key string,
   417  ) bool {
   418  	v, exist := parentMap[key]
   419  	if !exist {
   420  		return a.assert.Fail(fmt.Sprintf("'%s' does not have '%s'\n%#v", parentKey, key, parentMap))
   421  	}
   422  	if v != nil {
   423  		return a.assert.Fail(fmt.Sprintf("'%s.%s' is not nil", parentKey, key))
   424  	}
   425  	return true
   426  }
   427  
   428  func (a *aggregateResponseAssert) hasArray(parentMap map[string]interface{},
   429  	parentKey, key string, expectedValue []interface{},
   430  ) bool {
   431  	v, exist := parentMap[key]
   432  	if !exist {
   433  		return a.assert.Fail(fmt.Sprintf("'%s' does not have '%s'\n%#v", parentKey, key, parentMap))
   434  	}
   435  	if !a.assert.Equal(expectedValue, v) {
   436  		return a.assert.Fail(fmt.Sprintf("'%s.%s' of %#v is not equal to %#v", parentKey, key, v, expectedValue))
   437  	}
   438  	return true
   439  }
   440  
   441  func combinedAssert(assertResults ...bool) bool {
   442  	for _, assertResult := range assertResults {
   443  		if !assertResult {
   444  			return false
   445  		}
   446  	}
   447  	return true
   448  }