github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/issue_test/pretouch_test.go (about)

     1  /*
     2   * Copyright 2021 ByteDance Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package issue_test
    18  
    19  import (
    20  	"bytes"
    21  	"compress/gzip"
    22  	"encoding/json"
    23  	"io/ioutil"
    24  	"reflect"
    25  	"testing"
    26  	"time"
    27  
    28  	. "github.com/goshafaq/sonic"
    29  	"github.com/goshafaq/sonic/option"
    30  	"github.com/stretchr/testify/require"
    31  )
    32  
    33  var jsonData = func() string {
    34  	// Read and decompress the test data.
    35  	b, err := ioutil.ReadFile("../testdata/synthea_fhir.json.gz")
    36  	if err != nil {
    37  		panic(err)
    38  	}
    39  	zr, err := gzip.NewReader(bytes.NewReader(b))
    40  	if err != nil {
    41  		panic(err)
    42  	}
    43  	data, err := ioutil.ReadAll(zr)
    44  	if err != nil {
    45  		panic(err)
    46  	}
    47  	return string(data)
    48  }()
    49  
    50  type (
    51  	syntheaRoot struct {
    52  		Entry []struct {
    53  			FullURL string `json:"fullUrl"`
    54  			Request *struct {
    55  				Method string `json:"method"`
    56  				URL    string `json:"url"`
    57  			} `json:"request"`
    58  			Resource *struct {
    59  				AbatementDateTime time.Time   `json:"abatementDateTime"`
    60  				AchievementStatus syntheaCode `json:"achievementStatus"`
    61  				Active            bool        `json:"active"`
    62  				Activity          []struct {
    63  					Detail *struct {
    64  						Code     syntheaCode      `json:"code"`
    65  						Location syntheaReference `json:"location"`
    66  						Status   string           `json:"status"`
    67  					} `json:"detail"`
    68  				} `json:"activity"`
    69  				Address        []syntheaAddress   `json:"address"`
    70  				Addresses      []syntheaReference `json:"addresses"`
    71  				AuthoredOn     time.Time          `json:"authoredOn"`
    72  				BillablePeriod syntheaRange       `json:"billablePeriod"`
    73  				BirthDate      string             `json:"birthDate"`
    74  				CareTeam       []struct {
    75  					Provider  syntheaReference `json:"provider"`
    76  					Reference string           `json:"reference"`
    77  					Role      syntheaCode      `json:"role"`
    78  					Sequence  int64            `json:"sequence"`
    79  				} `json:"careTeam"`
    80  				Category       []syntheaCode    `json:"category"`
    81  				Claim          syntheaReference `json:"claim"`
    82  				Class          syntheaCoding    `json:"class"`
    83  				ClinicalStatus syntheaCode      `json:"clinicalStatus"`
    84  				Code           syntheaCode      `json:"code"`
    85  				Communication  []struct {
    86  					Language syntheaCode `json:"language"`
    87  				} `json:"communication"`
    88  				Component []struct {
    89  					Code          syntheaCode   `json:"code"`
    90  					ValueQuantity syntheaCoding `json:"valueQuantity"`
    91  				} `json:"component"`
    92  				Contained []struct {
    93  					Beneficiary  syntheaReference   `json:"beneficiary"`
    94  					ID           string             `json:"id"`
    95  					Intent       string             `json:"intent"`
    96  					Payor        []syntheaReference `json:"payor"`
    97  					Performer    []syntheaReference `json:"performer"`
    98  					Requester    syntheaReference   `json:"requester"`
    99  					ResourceType string             `json:"resourceType"`
   100  					Status       string             `json:"status"`
   101  					Subject      syntheaReference   `json:"subject"`
   102  					Type         syntheaCode        `json:"type"`
   103  				} `json:"contained"`
   104  				Created          time.Time   `json:"created"`
   105  				DeceasedDateTime time.Time   `json:"deceasedDateTime"`
   106  				Description      syntheaCode `json:"description"`
   107  				Diagnosis        []struct {
   108  					DiagnosisReference syntheaReference `json:"diagnosisReference"`
   109  					Sequence           int64            `json:"sequence"`
   110  					Type               []syntheaCode    `json:"type"`
   111  				} `json:"diagnosis"`
   112  				DosageInstruction []struct {
   113  					AsNeededBoolean bool `json:"asNeededBoolean"`
   114  					DoseAndRate     []struct {
   115  						DoseQuantity *struct {
   116  							Value float64 `json:"value"`
   117  						} `json:"doseQuantity"`
   118  						Type syntheaCode `json:"type"`
   119  					} `json:"doseAndRate"`
   120  					Sequence int64 `json:"sequence"`
   121  					Timing   *struct {
   122  						Repeat *struct {
   123  							Frequency  int64   `json:"frequency"`
   124  							Period     float64 `json:"period"`
   125  							PeriodUnit string  `json:"periodUnit"`
   126  						} `json:"repeat"`
   127  					} `json:"timing"`
   128  				} `json:"dosageInstruction"`
   129  				EffectiveDateTime time.Time          `json:"effectiveDateTime"`
   130  				Encounter         syntheaReference   `json:"encounter"`
   131  				Extension         []syntheaExtension `json:"extension"`
   132  				Gender            string             `json:"gender"`
   133  				Goal              []syntheaReference `json:"goal"`
   134  				ID                string             `json:"id"`
   135  				Identifier        []struct {
   136  					System string      `json:"system"`
   137  					Type   syntheaCode `json:"type"`
   138  					Use    string      `json:"use"`
   139  					Value  string      `json:"value"`
   140  				} `json:"identifier"`
   141  				Insurance []struct {
   142  					Coverage syntheaReference `json:"coverage"`
   143  					Focal    bool             `json:"focal"`
   144  					Sequence int64            `json:"sequence"`
   145  				} `json:"insurance"`
   146  				Insurer syntheaReference `json:"insurer"`
   147  				Intent  string           `json:"intent"`
   148  				Issued  time.Time        `json:"issued"`
   149  				Item    []struct {
   150  					Adjudication []struct {
   151  						Amount   syntheaCurrency `json:"amount"`
   152  						Category syntheaCode     `json:"category"`
   153  					} `json:"adjudication"`
   154  					Category                syntheaCode        `json:"category"`
   155  					DiagnosisSequence       []int64            `json:"diagnosisSequence"`
   156  					Encounter               []syntheaReference `json:"encounter"`
   157  					InformationSequence     []int64            `json:"informationSequence"`
   158  					LocationCodeableConcept syntheaCode        `json:"locationCodeableConcept"`
   159  					Net                     syntheaCurrency    `json:"net"`
   160  					ProcedureSequence       []int64            `json:"procedureSequence"`
   161  					ProductOrService        syntheaCode        `json:"productOrService"`
   162  					Sequence                int64              `json:"sequence"`
   163  					ServicedPeriod          syntheaRange       `json:"servicedPeriod"`
   164  				} `json:"item"`
   165  				LifecycleStatus           string             `json:"lifecycleStatus"`
   166  				ManagingOrganization      []syntheaReference `json:"managingOrganization"`
   167  				MaritalStatus             syntheaCode        `json:"maritalStatus"`
   168  				MedicationCodeableConcept syntheaCode        `json:"medicationCodeableConcept"`
   169  				MultipleBirthBoolean      bool               `json:"multipleBirthBoolean"`
   170  				Name                      json.RawMessage    `json:"name"`
   171  				NumberOfInstances         int64              `json:"numberOfInstances"`
   172  				NumberOfSeries            int64              `json:"numberOfSeries"`
   173  				OccurrenceDateTime        time.Time          `json:"occurrenceDateTime"`
   174  				OnsetDateTime             time.Time          `json:"onsetDateTime"`
   175  				Outcome                   string             `json:"outcome"`
   176  				Participant               []struct {
   177  					Individual syntheaReference `json:"individual"`
   178  					Member     syntheaReference `json:"member"`
   179  					Role       []syntheaCode    `json:"role"`
   180  				} `json:"participant"`
   181  				Patient syntheaReference `json:"patient"`
   182  				Payment *struct {
   183  					Amount syntheaCurrency `json:"amount"`
   184  				} `json:"payment"`
   185  				PerformedPeriod syntheaRange     `json:"performedPeriod"`
   186  				Period          syntheaRange     `json:"period"`
   187  				Prescription    syntheaReference `json:"prescription"`
   188  				PrimarySource   bool             `json:"primarySource"`
   189  				Priority        syntheaCode      `json:"priority"`
   190  				Procedure       []struct {
   191  					ProcedureReference syntheaReference `json:"procedureReference"`
   192  					Sequence           int64            `json:"sequence"`
   193  				} `json:"procedure"`
   194  				Provider        syntheaReference   `json:"provider"`
   195  				ReasonCode      []syntheaCode      `json:"reasonCode"`
   196  				ReasonReference []syntheaReference `json:"reasonReference"`
   197  				RecordedDate    time.Time          `json:"recordedDate"`
   198  				Referral        syntheaReference   `json:"referral"`
   199  				Requester       syntheaReference   `json:"requester"`
   200  				ResourceType    string             `json:"resourceType"`
   201  				Result          []syntheaReference `json:"result"`
   202  				Series          []struct {
   203  					BodySite syntheaCoding `json:"bodySite"`
   204  					Instance []struct {
   205  						Number   int64         `json:"number"`
   206  						SopClass syntheaCoding `json:"sopClass"`
   207  						Title    string        `json:"title"`
   208  						UID      string        `json:"uid"`
   209  					} `json:"instance"`
   210  					Modality          syntheaCoding `json:"modality"`
   211  					Number            int64         `json:"number"`
   212  					NumberOfInstances int64         `json:"numberOfInstances"`
   213  					Started           string        `json:"started"`
   214  					UID               string        `json:"uid"`
   215  				} `json:"series"`
   216  				ServiceProvider syntheaReference `json:"serviceProvider"`
   217  				Started         time.Time        `json:"started"`
   218  				Status          string           `json:"status"`
   219  				Subject         syntheaReference `json:"subject"`
   220  				SupportingInfo  []struct {
   221  					Category       syntheaCode      `json:"category"`
   222  					Sequence       int64            `json:"sequence"`
   223  					ValueReference syntheaReference `json:"valueReference"`
   224  				} `json:"supportingInfo"`
   225  				Telecom              []map[string]string `json:"telecom"`
   226  				Text                 map[string]string   `json:"text"`
   227  				Total                json.RawMessage     `json:"total"`
   228  				Type                 json.RawMessage     `json:"type"`
   229  				Use                  string              `json:"use"`
   230  				VaccineCode          syntheaCode         `json:"vaccineCode"`
   231  				ValueCodeableConcept syntheaCode         `json:"valueCodeableConcept"`
   232  				ValueQuantity        syntheaCoding       `json:"valueQuantity"`
   233  				VerificationStatus   syntheaCode         `json:"verificationStatus"`
   234  			} `json:"resource"`
   235  		} `json:"entry"`
   236  		ResourceType string `json:"resourceType"`
   237  		Type         string `json:"type"`
   238  	}
   239  	syntheaCode struct {
   240  		Coding []syntheaCoding `json:"coding"`
   241  		Text   string          `json:"text"`
   242  	}
   243  	syntheaCoding struct {
   244  		Code    string  `json:"code"`
   245  		Display string  `json:"display"`
   246  		System  string  `json:"system"`
   247  		Unit    string  `json:"unit"`
   248  		Value   float64 `json:"value"`
   249  	}
   250  	syntheaReference struct {
   251  		Display   string `json:"display"`
   252  		Reference string `json:"reference"`
   253  	}
   254  	syntheaAddress struct {
   255  		City       string             `json:"city"`
   256  		Country    string             `json:"country"`
   257  		Extension  []syntheaExtension `json:"extension"`
   258  		Line       []string           `json:"line"`
   259  		PostalCode string             `json:"postalCode"`
   260  		State      string             `json:"state"`
   261  	}
   262  	syntheaExtension struct {
   263  		URL          string             `json:"url"`
   264  		ValueAddress syntheaAddress     `json:"valueAddress"`
   265  		ValueCode    string             `json:"valueCode"`
   266  		ValueDecimal float64            `json:"valueDecimal"`
   267  		ValueString  string             `json:"valueString"`
   268  		Extension    []syntheaExtension `json:"extension"`
   269  	}
   270  	syntheaRange struct {
   271  		End   time.Time `json:"end"`
   272  		Start time.Time `json:"start"`
   273  	}
   274  	syntheaCurrency struct {
   275  		Currency string  `json:"currency"`
   276  		Value    float64 `json:"value"`
   277  	}
   278  )
   279  
   280  func TestPretouchSynteaRoot(t *testing.T) {
   281  	m := new(syntheaRoot)
   282  	s := time.Now()
   283  	println("start decoder pretouch:", s.UnixNano())
   284  	require.Nil(t, Pretouch(reflect.TypeOf(m), option.WithCompileMaxInlineDepth(2), option.WithCompileRecursiveDepth(20)))
   285  	e := time.Now()
   286  	println("end decoder pretouch:", e.UnixNano())
   287  	println("elapsed:", e.Sub(s).Milliseconds(), "ms")
   288  
   289  	s = time.Now()
   290  	println("start decode:", s.UnixNano())
   291  	require.Nil(t, UnmarshalString(jsonData, m))
   292  	e = time.Now()
   293  	println("end decode:", e.UnixNano())
   294  	d1 := e.Sub(s).Nanoseconds()
   295  	println("elapsed:", d1, "ns")
   296  
   297  	s = time.Now()
   298  	println("start decode:", s.UnixNano())
   299  	require.Nil(t, UnmarshalString(jsonData, m))
   300  	e = time.Now()
   301  	println("end decode:", e.UnixNano())
   302  	d2 := e.Sub(s).Nanoseconds()
   303  	println("elapsed:", d2, "ns")
   304  	if d1 > d2*20 {
   305  		t.Fatal("decoder pretouch not finish yet")
   306  	}
   307  
   308  	s = time.Now()
   309  	println("start decode:", s.UnixNano())
   310  	require.Nil(t, UnmarshalString(jsonData, m))
   311  	e = time.Now()
   312  	println("end decode:", e.UnixNano())
   313  	d5 := e.Sub(s).Nanoseconds()
   314  	println("elapsed:", d5, "ns")
   315  	if d2 > d5*10 {
   316  		t.Fatal("decoder pretouch not finish yet")
   317  	}
   318  
   319  	s = time.Now()
   320  	println("start encode 1:", s.UnixNano())
   321  	_, err := MarshalString(*m)
   322  	require.Nil(t, err)
   323  	e = time.Now()
   324  	println("end encode 1:", e.UnixNano())
   325  	d3 := e.Sub(s).Nanoseconds()
   326  	println("elapsed:", d3, "ns")
   327  
   328  	s = time.Now()
   329  	println("start encode 2:", s.UnixNano())
   330  	_, err = MarshalString(m)
   331  	require.Nil(t, err)
   332  	e = time.Now()
   333  	println("end encode 2:", e.UnixNano())
   334  	d4 := e.Sub(s).Nanoseconds()
   335  	println("elapsed:", d4, "ns")
   336  	// if d3 > d4 * 10 {
   337  	//     t.Fatal("encoder pretouch not finish yet")
   338  	// }
   339  
   340  	s = time.Now()
   341  	println("start encode 3:", s.UnixNano())
   342  	_, err = MarshalString(m)
   343  	require.Nil(t, err)
   344  	e = time.Now()
   345  	println("end encode 3:", e.UnixNano())
   346  	d6 := e.Sub(s).Nanoseconds()
   347  	println("elapsed:", d6, "ns")
   348  	if d4 > d6*10 {
   349  		t.Fatal("encoder pretouch not finish yet")
   350  	}
   351  }
   352  
   353  func BenchmarkDecodeSynteaRoot(b *testing.B) {
   354  	m := new(syntheaRoot)
   355  	require.Nil(b, Pretouch(reflect.TypeOf(m), option.WithCompileRecursiveDepth(10)))
   356  
   357  	b.SetBytes(int64(len(jsonData)))
   358  	b.ResetTimer()
   359  	for i := 0; i < b.N; i++ {
   360  		_ = UnmarshalString(jsonData, m)
   361  	}
   362  }
   363  
   364  func BenchmarkEncodeSynteaRoot(b *testing.B) {
   365  	m := new(syntheaRoot)
   366  	require.Nil(b, Pretouch(reflect.TypeOf(m), option.WithCompileRecursiveDepth(10)))
   367  	require.Nil(b, UnmarshalString(jsonData, m))
   368  
   369  	b.SetBytes(int64(len(jsonData)))
   370  	b.ResetTimer()
   371  	for i := 0; i < b.N; i++ {
   372  		_, _ = MarshalString(m)
   373  	}
   374  }