code: func (r *Runner) assertJSONIsEqualOrSubset(v1 interface{}, v2 interface{}) (bool, error) {
  	if (v1 == nil) && (v2 == nil) {
  		return true, nil
  	}
  
  	// check if both are non nil and that type matches
  	if ((v1 == nil) != (v2 == nil)) ||
  		(reflect.ValueOf(v1).Type() != reflect.ValueOf(v2).Type()) {
  		return false, fmt.Errorf("types do not match")
  	}
  
  	switch v1.(type) {
  	case map[string]interface{}:
  		// recursively check maps
  		// v2 is of same type as v1 as check in early return
  		v2map := v2.(map[string]interface{})
  		for objK, objV := range v1.(map[string]interface{}) {
  			if v2map[objK] == nil {
  				return false, fmt.Errorf("missing key '%s'", objK)
  			}
  			equalForKey, errForKey := r.assertJSONIsEqualOrSubset(objV, v2map[objK])
  			if !equalForKey {
  				return false, fmt.Errorf("mismatch for key '%s': %s", objK, errForKey)
  			}
  		}
  
  		return true, nil
  	default:
  		// all non-map types must be deep equal
  		if !reflect.DeepEqual(v1, v2) {
  			return false, fmt.Errorf("values do not match - %s != %s", v1, v2)
  		}
  		return true, nil
  	}
  }
docs: // assertJSONIsEqualOrSubset returns true if v1 and v2 are equal in value
  // or if both are maps (of type map[string]interface{}) and v1 is a subset of v2, where
  // all keys that are present in v1 are present with the same value in v2.