github.com/CycloneDX/sbom-utility@v0.16.0/cmd/query_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  /*
     3   * Licensed to the Apache Software Foundation (ASF) under one or more
     4   * contributor license agreements.  See the NOTICE file distributed with
     5   * this work for additional information regarding copyright ownership.
     6   * The ASF licenses this file to You under the Apache License, Version 2.0
     7   * (the "License"); you may not use this file except in compliance with
     8   * the License.  You may obtain a copy of the License at
     9   *
    10   *     http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  package cmd
    20  
    21  import (
    22  	"bufio"
    23  	"bytes"
    24  	"encoding/json"
    25  	"fmt"
    26  	"io"
    27  	"io/fs"
    28  	"os"
    29  	"testing"
    30  
    31  	"github.com/CycloneDX/sbom-utility/common"
    32  	"github.com/CycloneDX/sbom-utility/schema"
    33  	"github.com/CycloneDX/sbom-utility/utils"
    34  )
    35  
    36  // -------------------------------------------
    37  // test helper functions
    38  // -------------------------------------------
    39  
    40  func innerQueryError(t *testing.T, cti *CommonTestInfo, queryRequest *common.QueryRequest, expectedError error) (result interface{}, actualError error) {
    41  	getLogger().Enter()
    42  	defer getLogger().Exit()
    43  
    44  	result, _, actualError = innerQuery(t, cti, queryRequest)
    45  
    46  	// if the query resulted in a failure
    47  	if !ErrorTypesMatch(actualError, expectedError) {
    48  		getLogger().Tracef("expected error type: `%T`, actual type: `%T`", expectedError, actualError)
    49  		t.Errorf("expected error type: `%T`, actual type: `%T`", expectedError, actualError)
    50  	}
    51  	return
    52  }
    53  
    54  // NOTE: This function "mocks" what the "queryCmdImpl()" function would do
    55  func innerQuery(t *testing.T, cti *CommonTestInfo, queryRequest *common.QueryRequest) (resultJson interface{}, outputBuffer bytes.Buffer, err error) {
    56  	getLogger().Enter()
    57  	defer getLogger().Exit()
    58  
    59  	// Copy the test filename to the command line flags were the code looks for it
    60  	utils.GlobalFlags.PersistentFlags.InputFile = cti.InputFile
    61  
    62  	// allocate response/result object and invoke query
    63  	var queryResponse = new(common.QueryResponse)
    64  	resultJson, outputBuffer, err = innerBufferedTestQuery(cti, queryRequest, queryResponse)
    65  
    66  	// if the command resulted in a failure
    67  	if err != nil {
    68  		// if tests asks us to report a FAIL to the test framework
    69  		if cti.Autofail {
    70  			encodedTestInfo, _ := utils.EncodeAnyToDefaultIndentedJSONStr(queryRequest)
    71  			t.Errorf("%s: failed: %v\nQueryRequest:\n%s", cti.InputFile, err, encodedTestInfo.String())
    72  		}
    73  		return
    74  	}
    75  
    76  	// Log results if trace enabled
    77  	if err != nil {
    78  		var buffer bytes.Buffer
    79  		buffer, err = utils.EncodeAnyToDefaultIndentedJSONStr(resultJson)
    80  		// Output the JSON data directly to stdout (not subject to log-level)
    81  		getLogger().Tracef("%s\n", buffer.String())
    82  	}
    83  	return
    84  }
    85  
    86  func innerBufferedTestQuery(testInfo *CommonTestInfo, queryRequest *common.QueryRequest, queryResponse *common.QueryResponse) (resultJson interface{}, outputBuffer bytes.Buffer, err error) {
    87  
    88  	// The command looks for the input & output filename in global flags struct
    89  	utils.GlobalFlags.PersistentFlags.InputFile = testInfo.InputFile
    90  	utils.GlobalFlags.PersistentFlags.OutputFile = testInfo.OutputFile
    91  	utils.GlobalFlags.PersistentFlags.OutputFormat = testInfo.OutputFormat
    92  	utils.GlobalFlags.PersistentFlags.OutputIndent = testInfo.OutputIndent
    93  	var outputWriter io.Writer
    94  	var outputFile *os.File
    95  
    96  	// TODO: centralize this logic to a function all Commands can use...
    97  	// Note: Any "Mocking" of os.Stdin/os.Stdout should be done in functions that call this one
    98  	if testInfo.OutputFile == "" {
    99  		// Declare an output outputBuffer/outputWriter to use used during tests
   100  		bufferedWriter := bufio.NewWriter(&outputBuffer)
   101  		outputWriter = bufferedWriter
   102  		// MUST ensure all data is written to buffer before further testing
   103  		defer bufferedWriter.Flush()
   104  	} else {
   105  		outputFile, outputWriter, err = createOutputFile(testInfo.OutputFile)
   106  		getLogger().Tracef("outputFile: `%v`; writer: `%v`", testInfo.OutputFile, outputWriter)
   107  
   108  		// use function closure to assure consistent error output based upon error type
   109  		defer func() {
   110  			// always close the output file (even if error, as long as file handle returned)
   111  			if outputFile != nil {
   112  				outputFile.Close()
   113  				getLogger().Infof("Closed output file: `%s`", testInfo.OutputFile)
   114  			}
   115  		}()
   116  
   117  		if err != nil {
   118  			return
   119  		}
   120  	}
   121  
   122  	resultJson, err = Query(outputWriter, queryRequest, queryResponse)
   123  	return
   124  }
   125  
   126  // Used to help verify query results
   127  func UnmarshalResultsToMap(results interface{}) (resultMap map[string]interface{}, err error) {
   128  	getLogger().Enter()
   129  	defer getLogger().Exit()
   130  
   131  	// we need to marshal the data to normalize it to a []byte
   132  	var resultBytes []byte
   133  	resultBytes, err = json.Marshal(results)
   134  	if err != nil {
   135  		return
   136  	}
   137  
   138  	err = json.Unmarshal(resultBytes, &resultMap)
   139  	if err != nil {
   140  		return
   141  	}
   142  
   143  	return
   144  }
   145  
   146  // Used to verify fields specified on a SELECT clause appear in JSON results (map)
   147  func VerifySelectedFieldsInJsonMap(t *testing.T, keys []string, results interface{}) (exists bool, err error) {
   148  
   149  	if results == nil {
   150  		t.Errorf("invalid results: %v", results)
   151  	}
   152  
   153  	resultMap, err := UnmarshalResultsToMap(results)
   154  	if err != nil {
   155  		getLogger().Tracef("results: %v", resultMap)
   156  		t.Errorf("invalid JSON: %s: %v", err, resultMap)
   157  	}
   158  
   159  	for _, key := range keys {
   160  		_, exists = resultMap[key]
   161  		if !exists {
   162  			t.Errorf("invalid results: key: `%s` does not exist.", key)
   163  		}
   164  	}
   165  	return
   166  }
   167  
   168  // ----------------------------------------
   169  // Command flag tests
   170  // ----------------------------------------
   171  
   172  func TestQueryFailInvalidInputFileLoad(t *testing.T) {
   173  	cti := NewCommonTestInfoBasic(TEST_INPUT_FILE_NON_EXISTENT)
   174  	request, _ := common.NewQueryRequestSelectWildcardFrom(
   175  		"metadata.properties")
   176  	// Assure we return path error
   177  	_, _ = innerQueryError(t, cti, request, &fs.PathError{})
   178  }
   179  
   180  // ----------------------------------------
   181  // PASS tests
   182  // ----------------------------------------
   183  
   184  func TestQueryCdx14BomFormatSpecVersion(t *testing.T) {
   185  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   186  	request, _ := common.NewQueryRequestSelectFrom(
   187  		"bomFormat,specVersion",
   188  		"")
   189  	results, _ := innerQueryError(t, cti, request, nil)
   190  	_, _ = VerifySelectedFieldsInJsonMap(t, request.GetSelectKeys(), results)
   191  }
   192  
   193  func TestQueryCdx14MetadataTimestampField(t *testing.T) {
   194  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   195  	request, _ := common.NewQueryRequestSelectFrom(
   196  		"timestamp",
   197  		"metadata")
   198  	results, _ := innerQueryError(t, cti, request, nil)
   199  	_, _ = VerifySelectedFieldsInJsonMap(t, request.GetSelectKeys(), results)
   200  }
   201  
   202  func TestQueryCdx14MetadataComponentAll(t *testing.T) {
   203  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   204  	request, _ := common.NewQueryRequestSelectWildcardFrom(
   205  		"metadata.component")
   206  	results, _ := innerQueryError(t, cti, request, nil)
   207  	// Test for concrete keys that SHOULD have been found using wildcard
   208  	fields := []string{
   209  		"type", "bom-ref", "purl", "version", "externalReferences",
   210  		"name", "description", "licenses", "properties", "hashes",
   211  		"supplier", "publisher"}
   212  	_, _ = VerifySelectedFieldsInJsonMap(t, fields, results)
   213  }
   214  
   215  func TestQueryCdx14MetadataComponentNameDescriptionVersion(t *testing.T) {
   216  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   217  	request, _ := common.NewQueryRequestSelectFrom(
   218  		"name,description,version",
   219  		"metadata.component")
   220  	results, _ := innerQueryError(t, cti, request, nil)
   221  	_, _ = VerifySelectedFieldsInJsonMap(t, request.GetSelectKeys(), results)
   222  }
   223  
   224  func TestQueryCdx14MetadataSupplier(t *testing.T) {
   225  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   226  	request, _ := common.NewQueryRequestSelectFrom(
   227  		common.QUERY_TOKEN_WILDCARD,
   228  		"metadata.supplier")
   229  	results, _ := innerQueryError(t, cti, request, nil)
   230  	// Test for concrete keys that SHOULD have been found using wildcard
   231  	fields := []string{"name", "url", "contact"}
   232  	_, _ = VerifySelectedFieldsInJsonMap(t, fields, results)
   233  }
   234  
   235  func TestQueryCdx14MetadataManufacturer(t *testing.T) {
   236  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   237  	request, _ := common.NewQueryRequestSelectFrom(
   238  		common.QUERY_TOKEN_WILDCARD,
   239  		"metadata.manufacture")
   240  	results, _ := innerQueryError(t, cti, request, nil)
   241  	// Test for concrete keys that SHOULD have been found using wildcard
   242  	fields := []string{"name", "url", "contact"}
   243  	_, _ = VerifySelectedFieldsInJsonMap(t, fields, results)
   244  }
   245  
   246  func TestQueryCdx14MetadataComponentLicenses(t *testing.T) {
   247  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   248  	request, _ := common.NewQueryRequestSelectFrom(
   249  		"licenses",
   250  		"metadata.component")
   251  	results, _ := innerQueryError(t, cti, request, nil)
   252  	_, _ = VerifySelectedFieldsInJsonMap(t, request.GetSelectKeys(), results)
   253  }
   254  
   255  func TestQueryCdx14MetadataComponentSupplier(t *testing.T) {
   256  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   257  	request, _ := common.NewQueryRequestSelectFrom(
   258  		"supplier",
   259  		"metadata.component")
   260  	results, _ := innerQueryError(t, cti, request, nil)
   261  	_, _ = VerifySelectedFieldsInJsonMap(t, request.GetSelectKeys(), results)
   262  }
   263  
   264  func TestQueryCdx14MetadataComponentPublisher(t *testing.T) {
   265  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   266  	request, _ := common.NewQueryRequestSelectFrom(
   267  		"publisher",
   268  		"metadata.component")
   269  	results, _ := innerQueryError(t, cti, request, nil)
   270  	_, _ = VerifySelectedFieldsInJsonMap(t, request.GetSelectKeys(), results)
   271  }
   272  
   273  func TestQueryCdx14MetadataAllWithWildcard(t *testing.T) {
   274  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   275  	request, _ := common.NewQueryRequestSelectWildcardFrom(
   276  		"metadata.component")
   277  	results, _ := innerQueryError(t, cti, request, nil)
   278  	// Check for all known values that should be on the FROM object
   279  	fields := []string{"type", "bom-ref", "licenses", "properties", "publisher", "purl", "name", "description", "version", "externalReferences"}
   280  	_, _ = VerifySelectedFieldsInJsonMap(t, fields, results)
   281  }
   282  
   283  // NOTE: properties is an []interface
   284  func TestQueryCdx14MetadataComponentProperties(t *testing.T) {
   285  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   286  	request, _ := common.NewQueryRequestSelectFrom(
   287  		"properties",
   288  		"metadata.component")
   289  	results, _ := innerQueryError(t, cti, request, nil)
   290  	_, _ = VerifySelectedFieldsInJsonMap(t, request.GetSelectKeys(), results)
   291  }
   292  
   293  // ----------------------------------------
   294  // FAIL tests
   295  // ----------------------------------------
   296  
   297  func TestQueryFailSpdx22Metadata(t *testing.T) {
   298  	cti := NewCommonTestInfoBasic(TEST_SPDX_2_2_MIN_REQUIRED)
   299  	request, _ := common.NewQueryRequestSelectFrom(
   300  		common.QUERY_TOKEN_WILDCARD,
   301  		"metadata")
   302  	// Expect a QueryError
   303  	_, _ = innerQueryError(t, cti, request, &schema.UnsupportedFormatError{})
   304  }
   305  
   306  func TestQueryFailCdx14MetadataComponentInvalidKey(t *testing.T) {
   307  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   308  	request, _ := common.NewQueryRequestSelectFrom(
   309  		common.QUERY_TOKEN_WILDCARD,
   310  		"metadata.component.foo")
   311  	expectedErrorStrings := []string{
   312  		common.MSG_QUERY_INVALID_FROM_CLAUSE,
   313  		MSG_QUERY_ERROR_FROM_KEY_NOT_FOUND,
   314  	}
   315  
   316  	// Expect a QueryError
   317  	_, err := innerQueryError(t, cti, request, &common.QueryError{})
   318  
   319  	// Assure we received an error with the expected key phrases
   320  	EvaluateErrorAndKeyPhrases(t, err, expectedErrorStrings)
   321  }
   322  
   323  func TestQueryFailCdx14MetadataComponentInvalidDataType(t *testing.T) {
   324  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   325  	request, _ := common.NewQueryRequestSelectFrom(
   326  		common.QUERY_TOKEN_WILDCARD,
   327  		"metadata.component.name")
   328  	// Expect a QueryResultInvalidTypeError
   329  	innerQueryError(t, cti, request, &common.QueryResultInvalidTypeError{})
   330  }
   331  
   332  func TestQueryFailCdx14MetadataComponentInvalidSelectClause(t *testing.T) {
   333  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   334  	request, _ := common.NewQueryRequestSelectFrom(
   335  		"name,*",
   336  		"metadata.component")
   337  	expectedErrorStrings := []string{
   338  		common.MSG_QUERY_INVALID_SELECT_CLAUSE,
   339  		MSG_QUERY_ERROR_SELECT_WILDCARD,
   340  	}
   341  	// Expect a QueryError
   342  	_, err := innerQueryError(t, cti, request, &common.QueryError{})
   343  	// Assure we received an error with the expected key phrases
   344  	EvaluateErrorAndKeyPhrases(t, err, expectedErrorStrings)
   345  }
   346  
   347  func TestQueryFailCdx14InvalidFromClauseWithArray(t *testing.T) {
   348  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   349  	request, _ := common.NewQueryRequestSelectFrom(
   350  		common.QUERY_TOKEN_WILDCARD,
   351  		"metadata.properties.name")
   352  	expectedErrorStrings := []string{
   353  		common.MSG_QUERY_INVALID_FROM_CLAUSE,
   354  		MSG_QUERY_ERROR_FROM_KEY_SLICE_DEREFERENCE,
   355  	}
   356  	// Expect a QueryError
   357  	_, err := innerQueryError(t, cti, request, &common.QueryError{})
   358  	// Assure we received an error with the expected key phrases
   359  	EvaluateErrorAndKeyPhrases(t, err, expectedErrorStrings)
   360  }
   361  
   362  // ----------------------------------------
   363  // WHERE clause tests
   364  // ----------------------------------------
   365  
   366  // Force a bad WHERE clause; expect a QueryError
   367  func TestQueryCdx14InvalidWhereClauseNoRegex(t *testing.T) {
   368  	_, err := common.NewQueryRequestSelectFromWhere(
   369  		common.QUERY_TOKEN_WILDCARD,
   370  		"metadata.properties",
   371  		"name")
   372  	// Note: this tests the parameter parsing function
   373  	// TODO: move to "common" package
   374  	if !ErrorTypesMatch(err, &common.QueryError{}) {
   375  		t.Errorf("expected error type: `%T`, actual type: `%T`", &common.QueryError{}, err)
   376  	}
   377  	expectedErrorStrings := []string{
   378  		common.MSG_QUERY_INVALID_WHERE_CLAUSE,
   379  	}
   380  	// Assure we received an error with the expected key phrases
   381  	EvaluateErrorAndKeyPhrases(t, err, expectedErrorStrings)
   382  }
   383  
   384  func TestQueryCdx14InvalidWhereClauseMultipleRegex(t *testing.T) {
   385  	_, err := common.NewQueryRequestSelectFromWhere(
   386  		common.QUERY_TOKEN_WILDCARD,
   387  		"metadata.properties",
   388  		"name=foo,value=bar=idk")
   389  	if !ErrorTypesMatch(err, &common.QueryError{}) {
   390  		t.Errorf("expected error type: `%T`, actual type: `%T`", &common.QueryError{}, err)
   391  	}
   392  	expectedErrorStrings := []string{
   393  		common.MSG_QUERY_INVALID_WHERE_CLAUSE,
   394  	}
   395  	// Assure we received an error with the expected key phrases
   396  	EvaluateErrorAndKeyPhrases(t, err, expectedErrorStrings)
   397  }
   398  
   399  func TestQueryCdx14InvalidWhereClauseEmptyRegex(t *testing.T) {
   400  	_, err := common.NewQueryRequestSelectFromWhere(
   401  		common.QUERY_TOKEN_WILDCARD,
   402  		"metadata.properties",
   403  		"name=foo,value=")
   404  	if !ErrorTypesMatch(err, &common.QueryError{}) {
   405  		t.Errorf("expected error type: `%T`, actual type: `%T`", &common.QueryError{}, err)
   406  	}
   407  	expectedErrorStrings := []string{
   408  		common.MSG_QUERY_INVALID_WHERE_CLAUSE,
   409  	}
   410  	// Assure we received an error with the expected key phrases
   411  	EvaluateErrorAndKeyPhrases(t, err, expectedErrorStrings)
   412  }
   413  
   414  func TestQueryCdx14RequiredDataLegalDisclaimer(t *testing.T) {
   415  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   416  	request, errNew := common.NewQueryRequestSelectFromWhere(
   417  		common.QUERY_TOKEN_WILDCARD,
   418  		"metadata.properties",
   419  		"name=urn:example.com:classification")
   420  	if errNew != nil {
   421  		t.Errorf("%s: %v", ERR_TYPE_UNEXPECTED_ERROR, errNew)
   422  	}
   423  
   424  	// WARN!!!! TODO: handle error tests locally until code is complete
   425  	result, _, err := innerQuery(t, cti, request)
   426  	if err != nil {
   427  		t.Errorf("%s: %v", ERR_TYPE_UNEXPECTED_ERROR, err)
   428  	}
   429  
   430  	properties, errUnMarshal := schema.UnMarshalProperties(result)
   431  
   432  	// TODO: declare error message as a constant
   433  	if errUnMarshal != nil {
   434  		t.Errorf("invalid `properties` data: %v", errUnMarshal)
   435  	}
   436  
   437  	// TODO: verify WHERE clause props. are returned
   438  	getLogger().Debugf("%v", properties)
   439  }
   440  
   441  func TestQueryCdx14InvalidWhereClauseOnFromSingleton(t *testing.T) {
   442  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   443  	request, _ := common.NewQueryRequestSelectFromWhere(
   444  		common.QUERY_TOKEN_WILDCARD,
   445  		"metadata.component",
   446  		"name=foo")
   447  	// Note: this produces a warning, not an error
   448  	_, err := innerQueryError(t, cti, request, nil)
   449  	if err != nil {
   450  		t.Error(err)
   451  	}
   452  }
   453  
   454  func TestQueryCdx14MetadataToolsSlice(t *testing.T) {
   455  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   456  	request, _ := common.NewQueryRequestSelectFromWhere(
   457  		common.QUERY_TOKEN_WILDCARD,
   458  		"metadata.tools",
   459  		"")
   460  	result, err := innerQueryError(t, cti, request, nil)
   461  	if err != nil {
   462  		t.Error(err)
   463  	}
   464  	if !utils.IsJsonSliceType(result) {
   465  		fResult, _ := utils.EncodeAnyToDefaultIndentedJSONStr(result)
   466  		t.Error(fmt.Errorf("expected JSON slice. Actual result: %s", fResult.String()))
   467  	}
   468  
   469  	// verify slice length and contents
   470  	slice := result.([]interface{})
   471  	EXPECTED_SLICE_LENGTH := 2
   472  	if actualLength := len(slice); actualLength != EXPECTED_SLICE_LENGTH {
   473  		fResult, _ := utils.EncodeAnyToDefaultIndentedJSONStr(result)
   474  		t.Error(fmt.Errorf("expected slice length: %v, actual length: %v. Actual result: %s", EXPECTED_SLICE_LENGTH, actualLength, fResult.String()))
   475  	}
   476  }
   477  
   478  func TestQueryCdx14MetadataToolsSliceWhereName(t *testing.T) {
   479  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   480  	cti.ResultExpectedLineCount = 24
   481  	request, _ := common.NewQueryRequestSelectFromWhere(
   482  		common.QUERY_TOKEN_WILDCARD,
   483  		"components",
   484  		"name=body-parser")
   485  	result, err := innerQueryError(t, cti, request, nil)
   486  	if err != nil {
   487  		t.Error(err)
   488  	}
   489  	if !utils.IsJsonSliceType(result) {
   490  		fResult, _ := utils.EncodeAnyToDefaultIndentedJSONStr(result)
   491  		t.Error(fmt.Errorf("expected JSON slice. Actual result: %s", fResult.String()))
   492  	}
   493  
   494  	// verify slice length and contents
   495  	slice := result.([]interface{})
   496  	EXPECTED_SLICE_LENGTH := 1
   497  	if actualLength := len(slice); actualLength != EXPECTED_SLICE_LENGTH {
   498  		fResult, _ := utils.EncodeAnyToDefaultIndentedJSONStr(result)
   499  		t.Error(fmt.Errorf("expected slice length: %v, actual length: %v. Actual result: %s", EXPECTED_SLICE_LENGTH, actualLength, fResult.String()))
   500  	}
   501  	buffer, _ := utils.EncodeAnyToIndentedJSONStr(result, utils.DEFAULT_JSON_INDENT_STRING)
   502  	verifyFileLineCountAndIndentation(t, buffer, cti)
   503  }
   504  
   505  func TestQueryCdx14MetadataComponentIndent(t *testing.T) {
   506  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   507  	cti.ResultExpectedLineCount = 6
   508  	cti.ResultExpectedIndentLength = DEFAULT_OUTPUT_INDENT_LENGTH
   509  	cti.ResultExpectedIndentAtLineNum = 1
   510  	request, _ := common.NewQueryRequestSelectFrom(
   511  		"name,description,version",
   512  		"metadata.component")
   513  
   514  	// Verify that JSON returned by the query command is able to apply default space indent
   515  	results, _ := innerQueryError(t, cti, request, nil)
   516  	buffer, _ := utils.EncodeAnyToIndentedJSONStr(results, utils.DEFAULT_JSON_INDENT_STRING)
   517  	// Validate output data
   518  	verifyFileLineCountAndIndentation(t, buffer, cti)
   519  }
   520  
   521  func TestQueryCdx14MetadataComponentIndentedFileWrite(t *testing.T) {
   522  	cti := NewCommonTestInfoBasic(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   523  	cti.OutputFile = cti.CreateTemporaryTestOutputFilename(TEST_CDX_1_4_MATURE_EXAMPLE_1_BASE)
   524  	cti.OutputIndent = 3
   525  	cti.ResultExpectedLineCount = 6
   526  	cti.ResultExpectedIndentLength = int(cti.OutputIndent)
   527  	cti.ResultExpectedIndentAtLineNum = 1
   528  	request, _ := common.NewQueryRequestSelectFrom(
   529  		"name,description,version",
   530  		"metadata.component")
   531  	_, err := innerQueryError(t, cti, request, nil)
   532  	if err != nil {
   533  		t.Error(err)
   534  	}
   535  
   536  	var pBuffer *bytes.Buffer
   537  	pBuffer, err = bufferFile(cti.OutputFile)
   538  	if err != nil {
   539  		t.Error(err)
   540  	}
   541  	// Validate output data
   542  	verifyFileLineCountAndIndentation(t, *pBuffer, cti)
   543  }