Search code examples
groovy

Groovy: Compare a response with a json file while ignoring certain keys


I have a response from a REST API with ~40k lines and I need to verify if the values in it match those in an already existing local file. The response does have a certain element which is dynamic and is based on the date and time the response has been received.

I need to compare the response with the local json file and make sure the values match, while ignoring that specific date&time element that comes through.

This is a snippet example of the response/json file:

[
   {
      "code" : "SJM",
      "valuesCount" : [
         {
            "code" : "SJM",
            "description" : "LAST_NAME FIRST_NAME-SJM (LMM/null)",
            "period" : "November 2020",
            "printedOn" : "31/01/2022 09:39:39",
            "name" : "null",
            "logo" : { },
            "standardId" : true,
            "dailyValues" : [
               {
                  "index" : "odd",
                  "day" : "01",
                  "description" : "",
                  "time" : "23:59",
                  "cms" : "",
                  "hcv" : "",
                  "nm" : "",
                  "hcp" : "",
                  "hcz" : "",
                  "synDc" : "",
                  "jiJnm" : "",
                  "c1" : "",
                  "c2" : "",
                  "proHvs" : "",
                  "dcd" : "",
                  "dcs" : "",
                  "d1" : "",
                  "d2" : "",
                  "nbdays" : ""
               },
            ]
         }
    }
  ]
]

The file contains hundreds of code entries, each with their own valuesCount maps, in which the the printedOn element appears and that's what I'm trying to ignore.

I've been trying to do this in Groovy and the only thing I've managed to find in the groovy docs is the removeAll() method thinking I could perhaps remove that key:value entirely but I don't think I'm using it right.

import groovy.json.*

def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def projectDir = groovyUtils.projectPath

def response = new JsonSlurper().parseText(context.expand( '${Request#Response}' ))
File jsonFile = new File(projectDir, "/Project/Resources/jsonFile.json")
def defaultValues = new JsonSlurper().parse(jsonFile)




var1 = response.removeAll{"printedOn"}

var2 = defaultValues.removeAll{"printedOn"}

   if (var1 == var2) {
    log.info "The request matches the default values."
   } else {
    throw new Exception("The request does not match the default values.");
   }

This just returns a true statement for both cases.

Could anyone point me in the right direction? Much appreciated.


Solution

  • You need to traverse into the hierarchy of lists/maps to alter the inner map and remove the printedOn key/value pair.

    Also your json is broken with missing/extra brackets.

    The following code:

    import groovy.json.*
    
    def data1 = '''\
    [
      {
        "code": "SJM",
        "valuesCount": [
          {
            "code": "SJM",
            "description": "LAST_NAME FIRST_NAME-SJM (LMM/null)",
            "period": "November 2020",
            "printedOn": "31/01/2022 09:39:39",
            "name": "null",
            "logo": {},
            "standardId": true,
            "dailyValues": [
              {
                "index": "odd",
                "day": "01",
                "description": "",
                "time": "23:59",
                "cms": "",
                "hcv": "",
                "nm": "",
                "hcp": "",
                "hcz": "",
                "synDc": "",
                "jiJnm": "",
                "c1": "",
                "c2": "",
                "proHvs": "",
                "dcd": "",
                "dcs": "",
                "d1": "",
                "d2": "",
                "nbdays": ""
              }
            ]
          }
        ]
      }
    ]'''
    
    
    def data2 = '''\
    [
      {
        "code": "SJM",
        "valuesCount": [
          {
            "code": "SJM",
            "description": "LAST_NAME FIRST_NAME-SJM (LMM/null)",
            "period": "November 2020",
            "printedOn": "25/11/2021 09:39:39",
            "name": "null",
            "logo": {},
            "standardId": true,
            "dailyValues": [
              {
                "index": "odd",
                "day": "01",
                "description": "",
                "time": "23:59",
                "cms": "",
                "hcv": "",
                "nm": "",
                "hcp": "",
                "hcz": "",
                "synDc": "",
                "jiJnm": "",
                "c1": "",
                "c2": "",
                "proHvs": "",
                "dcd": "",
                "dcs": "",
                "d1": "",
                "d2": "",
                "nbdays": ""
              }
            ]
          }
        ]
      }
    ]'''
    
    def parser = new JsonSlurper()
    def json1 = parser.parseText(data1)
    def json2 = parser.parseText(data2)
    
    def clean1 = removeNoise(json1)
    def clean2 = removeNoise(json2)
    
    def out1 = JsonOutput.toJson(clean1)
    def out2 = JsonOutput.toJson(clean2)
    
    assert out1 == out2
    
    if(out1 == out2) println "the two documents are identical"
    else             println "the two documents differ"
    
    def removeNoise(json) {
      json.collect { codeMap -> 
        codeMap.valuesCount = codeMap.valuesCount.collect { valuesMap -> 
          valuesMap.remove('printedOn')
          valuesMap
        }
        codeMap
      }
    }
    

    will produce the following output when executed:

    ─➤ groovy solution.groovy                                                                                
    the two documents are identical
    
    ─➤ 
    

    The json in the above code has been corrected to be parseable. I manually changed the string dates so that data1 and data2 differ on the printedOn property.

    edit - it seems that you can actually just do:

    assert clean1 == clean2
    // or 
    if (clean1 == clean2) ...
    

    for the comparison. Cuts out the extra serialization step to json but also leaves me feeling a tad uncomfortable with trusting groovy to do the right thing when comparing a nested data structure like this.

    I would probably still go with the serialization.