Best Go-testdeep code snippet using json.fatal
simplify.go
Source:simplify.go
1// simplify takes a wordy abstract representation of the MMPL in json2// and converts it to a more compact set of structures that map onto3// a json structure for easy i/o in other settings.4// This tool will only ever be run once to generate the compact representation.5package main6import (7 "encoding/json"8 "fmt"9 "io/ioutil"10 "log"11 "os"12 "strconv"13)14type MMPL struct {15 Atoms []Atom `json:"atoms"`16 Groups []Group `json:"groups"`17 Chains []Chain `json:"chains"`18 Molecules []Molecule `json:"molecules"`19 BondTypes []BondType `json:"bonds"`20 AngleTypes []AngleType `json:"angles"`21 TorsionTypes []TorsionType `json:"torsions"`22}23type Atom struct {24 Mass float64 `json:"mass"`25 R float64 `json:"r"`26 Epsilon float64 `json:"epsilon"`27 Names []string `json:"names"`28 Comment string `json:"comment"`29}30type Group struct {31 Name string `json:"name"`32 Atoms []GroupAtom `json:"atoms"`33 Bonds []GroupBond `json:"bonds"`34 Comment string `json:"comment"`35}36type GroupAtom struct {37 Name string `json:"name"`38 Q float64 `json:"q"`39 Index int `json:"index"`40 Comment string `json:"comment"`41}42type GroupBond struct {43 AtomIndexA int `json:"atom_index_A"`44 AtomIndexB int `json:"atom_index_B"`45 Comment string `json:"comment"`46}47type ChainBond struct {48 GroupIndexA int `json:"group_index_A"`49 AtomIndexA int `json:"atom_index_A"`50 GroupIndexB int `json:"group_index_B"`51 AtomIndexB int `json:"atom_index_B"`52 Comment string `json:"comment"`53}54type MoleculeBond struct {55 ChainIndexA int `json:"chain_index_A"`56 GroupIndexA int `json:"group_index_A"`57 AtomIndexA int `json:"atom_index_A"`58 ChainIndexB int `json:"chain_index_B"`59 GroupIndexB int `json:"group_index_B"`60 AtomIndexB int `json:"atom_index_B"`61 Comment string `json:"comment"`62}63type Chains struct {64 Chains []Chain `json:"chains"`65}66type Chain struct {67 Name string `json:"name"`68 Groups []ChainGroup `json:"groups"`69 Names []ChainGroupName `json:"names"`70 Bonds []ChainBond `json:"bonds"`71 Comment string `json:"comment"`72}73type ChainGroup struct {74 Name string `json:"name"`75 Index int `json:"index"`76 Comment string `json:"comment"`77}78type ChainGroupName struct {79 Name string `json:"name"`80 GroupIndex int `json:"group_index"`81 AtomIndex int `json:"atom_index"`82 Comment string `json:"comment"`83}84type Molecules struct {85 Molecules []Molecules `json:"molecules"`86}87type Molecule struct {88 Name string `json:"name"`89 Comment string `json:"comment"`90 Chains []MoleculeChain `json:"chains"`91 Bonds []MoleculeBond `json:"bonds"`92}93type MoleculeChain struct {94 Name string `json:"name"`95 Index int `json:"index"`96 Comment string `json:"comment"`97}98type BondType struct {99 NameA string `json:"name_A"`100 NameB string `json:"name_B"`101 L float64 `json:"l"`102 K float64 `json:"k"`103 Comment string `json:"comment"`104}105type AngleType struct {106 NameA string `json:"name_A"`107 NameB string `json:"name_B"`108 NameC string `json:"name_C"`109 Theta float64 `json:"theta"`110 K float64 `json:"k"`111 Comment string `json:"comment"`112}113type TorsionType struct {114 NameA string `json:"name_A"`115 NameB string `json:"name_B"`116 NameC string `json:"name_C"`117 NameD string `json:"name_D"`118 Type int `json:"type"`119 Phi float64 `json:"phi"`120 N int `json:"n"`121 K float64 `json:"k"`122 Comment string `json:"comment"`123}124func unpackAtom(m map[string]interface{}) Atom {125 mass, err := strconv.ParseFloat(m["mass"].(string), 64)126 if err != nil {127 log.Fatal(err)128 }129 epsilon, err := strconv.ParseFloat(m["epsilon"].(string), 64)130 if err != nil {131 log.Fatal(err)132 }133 r, err := strconv.ParseFloat(m["r"].(string), 64)134 if err != nil {135 log.Fatal(err)136 }137 cmt, ok := m["comment"].(string)138 if !ok {139 cmt = ""140 }141 names := []string{}142 nlist, ok := m["names"].(map[string]interface{})["n"]143 for _, v := range nlist.([]interface{}) {144 if mv, ok := v.(map[string]interface{}); ok {145 names = append(names, mv["name"].(string))146 }147 }148 atom := Atom{149 Epsilon: epsilon, Mass: mass, R: r,150 Names: names,151 Comment: cmt}152 return atom153}154func unpackGroup(m map[string]interface{}) Group {155 name, ok := m["name"].(string)156 if !ok {157 log.Fatal("unable to find name for group")158 }159 cmt, ok := m["comment"].(string)160 if !ok {161 cmt = ""162 }163 atoms := []GroupAtom{}164 alist, ok := m["atoms"].(map[string]interface{})["a"]165 if !ok {166 log.Fatal("unable to find list of atoms for group")167 }168 for _, v := range alist.([]interface{}) {169 if mv, ok := v.(map[string]interface{}); ok {170 mvname, ok := mv["name"].(string)171 if !ok {172 log.Fatal("in group, unable to find name of atom")173 }174 q, err := strconv.ParseFloat(mv["q"].(string), 64)175 if err != nil {176 log.Fatal(err)177 }178 idx, err := strconv.Atoi(mv["idx"].(string))179 if err != nil {180 log.Fatal(err)181 }182 agcmt, ok := mv["comment"].(string)183 if !ok {184 agcmt = ""185 }186 atoms = append(atoms, GroupAtom{187 Name: mvname,188 Q: q,189 Index: idx,190 Comment: agcmt,191 })192 }193 }194 bonds := []GroupBond{}195 blist, ok := m["bonds"].([]interface{})196 //if !ok {197 //log.Fatal("unable to find list of bonds for group")198 //}199 if len(blist) > 0 {200 blist0 := blist[0].(map[string]interface{})201 bs := blist0["b"].([]interface{})202 //fmt.Printf("%T\n", bs)203 for _, v := range bs {204 mv := v.(map[string]interface{})205 aia, err := strconv.Atoi(mv["atom_idx_A"].(string))206 if err != nil {207 log.Fatal(err)208 }209 aib, err := strconv.Atoi(mv["atom_idx_B"].(string))210 if err != nil {211 log.Fatal(err)212 }213 bcmt, ok := mv["comment"].(string)214 if !ok {215 bcmt = ""216 }217 bond := GroupBond{218 AtomIndexA: aia,219 AtomIndexB: aib,220 Comment: bcmt,221 }222 bonds = append(bonds, bond)223 }224 }225 group := Group{Name: name,226 Atoms: atoms,227 Bonds: bonds,228 Comment: cmt}229 return group230}231func unpackChain(m map[string]interface{}) Chain {232 name, ok := m["name"].(string)233 if !ok {234 log.Fatal("unable to find name for group")235 }236 cmt, ok := m["comment"].(string)237 if !ok {238 cmt = ""239 }240 groups := []ChainGroup{}241 glist, ok := m["groups"].(map[string]interface{})["g"]242 if !ok {243 log.Fatal("unable to find list of groups for chain")244 }245 for _, v := range glist.([]interface{}) {246 if mv, ok := v.(map[string]interface{}); ok {247 mvname, ok := mv["name"].(string)248 if !ok {249 log.Fatal("in chain, unable to find name of group")250 }251 idx, err := strconv.Atoi(mv["idx"].(string))252 if err != nil {253 log.Fatal(err)254 }255 agcmt, ok := mv["comment"].(string)256 if !ok {257 agcmt = ""258 }259 groups = append(groups, ChainGroup{260 Name: mvname,261 Index: idx,262 Comment: agcmt,263 })264 }265 }266 names := []ChainGroupName{}267 nlist, ok := m["names"].(map[string]interface{})268 if !ok {269 log.Println("chain with no names:", name)270 } else {271 nlist, ok := nlist["n"]272 if !ok {273 log.Fatal("found names array but no n array, giving up parsing")274 }275 for _, v := range nlist.([]interface{}) {276 mv := v.(map[string]interface{})277 mvname, ok := mv["name"].(string)278 if !ok {279 log.Fatal("unable to find name for chain atom")280 }281 atm_idx, err := strconv.Atoi(mv["group_idx"].(string))282 if err != nil {283 log.Fatal(err)284 }285 grp_idx, err := strconv.Atoi(mv["atom_idx"].(string))286 if err != nil {287 log.Fatal(err)288 }289 nameo := ChainGroupName{290 Name: mvname,291 AtomIndex: atm_idx,292 GroupIndex: grp_idx,293 }294 names = append(names, nameo)295 }296 }297 bonds := []ChainBond{}298 blist, ok := m["bonds"].([]interface{})299 //if !ok {300 //log.Fatal("unable to find list of bonds for group")301 //}302 if len(blist) > 0 {303 blist0 := blist[0].(map[string]interface{})304 bs := blist0["b"].([]interface{})305 //fmt.Printf("%T\n", bs)306 for _, v := range bs {307 mv := v.(map[string]interface{})308 aia, err := strconv.Atoi(mv["atom_idx_A"].(string))309 if err != nil {310 log.Fatal(err)311 }312 gia, err := strconv.Atoi(mv["group_idx_A"].(string))313 if err != nil {314 log.Fatal(err)315 }316 aib, err := strconv.Atoi(mv["atom_idx_B"].(string))317 if err != nil {318 log.Fatal(err)319 }320 gib, err := strconv.Atoi(mv["group_idx_B"].(string))321 if err != nil {322 log.Fatal(err)323 }324 bcmt, ok := mv["comment"].(string)325 if !ok {326 bcmt = ""327 }328 bond := ChainBond{329 AtomIndexA: aia,330 GroupIndexA: gia,331 AtomIndexB: aib,332 GroupIndexB: gib,333 Comment: bcmt,334 }335 bonds = append(bonds, bond)336 }337 }338 chain := Chain{Name: name,339 Groups: groups,340 Names: names,341 Bonds: bonds,342 Comment: cmt}343 return chain344}345func unpackMolecule(m map[string]interface{}) Molecule {346 name, ok := m["name"].(string)347 if !ok {348 log.Fatal("unable to find name for group")349 }350 cmt, ok := m["comment"].(string)351 if !ok {352 cmt = ""353 }354 chains := []MoleculeChain{}355 clist, ok := m["residues"].(map[string]interface{})["r"]356 if !ok {357 log.Fatal("unable to find list of atoms for group")358 }359 for _, v := range clist.([]interface{}) {360 if mv, ok := v.(map[string]interface{}); ok {361 mvname, ok := mv["name"].(string)362 if !ok {363 log.Fatal("in group, unable to find name of atom")364 }365 idx, err := strconv.Atoi(mv["idx"].(string))366 if err != nil {367 log.Fatal(err)368 }369 agcmt, ok := mv["comment"].(string)370 if !ok {371 agcmt = ""372 }373 chains = append(chains, MoleculeChain{374 Name: mvname,375 Index: idx,376 Comment: agcmt,377 })378 }379 }380 bonds := []MoleculeBond{}381 blist, ok := m["bonds"].([]interface{})382 //if !ok {383 //log.Fatal("unable to find list of bonds for group")384 //}385 if len(blist) > 0 {386 blist0 := blist[0].(map[string]interface{})387 bs := blist0["b"].([]interface{})388 //fmt.Printf("%T\n", bs)389 for _, v := range bs {390 mv := v.(map[string]interface{})391 aia, err := strconv.Atoi(mv["atom_idx_A"].(string))392 if err != nil {393 log.Fatal(err)394 }395 gia, err := strconv.Atoi(mv["group_idx_A"].(string))396 if err != nil {397 log.Fatal(err)398 }399 cia, err := strconv.Atoi(mv["chain_idx_A"].(string))400 if err != nil {401 log.Fatal(err)402 }403 aib, err := strconv.Atoi(mv["atom_idx_B"].(string))404 if err != nil {405 log.Fatal(err)406 }407 gib, err := strconv.Atoi(mv["group_idx_B"].(string))408 if err != nil {409 log.Fatal(err)410 }411 cib, err := strconv.Atoi(mv["chain_idx_B"].(string))412 if err != nil {413 log.Fatal(err)414 }415 bcmt, ok := mv["comment"].(string)416 if !ok {417 bcmt = ""418 }419 bond := MoleculeBond{420 ChainIndexA: cia,421 AtomIndexA: aia,422 GroupIndexA: gia,423 ChainIndexB: cib,424 AtomIndexB: aib,425 GroupIndexB: gib,426 Comment: bcmt,427 }428 bonds = append(bonds, bond)429 }430 }431 molecule := Molecule{Name: name,432 Chains: chains,433 Bonds: bonds,434 Comment: cmt}435 return molecule436}437func unpackBond(m map[string]interface{}) BondType {438 l, err := strconv.ParseFloat(m["l"].(string), 64)439 if err != nil {440 log.Fatal(err)441 }442 k, err := strconv.ParseFloat(m["k"].(string), 64)443 if err != nil {444 log.Fatal(err)445 }446 cmt, ok := m["comment"].(string)447 if !ok {448 cmt = ""449 }450 bondType := BondType{451 NameA: m["A"].(string), NameB: m["B"].(string),452 L: l, K: k,453 Comment: cmt}454 return bondType455}456func unpackAngle(m map[string]interface{}) AngleType {457 theta, err := strconv.ParseFloat(m["theta"].(string), 64)458 if err != nil {459 log.Fatal(err)460 }461 k, err := strconv.ParseFloat(m["k"].(string), 64)462 if err != nil {463 log.Fatal(err)464 }465 cmt, ok := m["comment"].(string)466 if !ok {467 cmt = ""468 }469 angleType := AngleType{470 NameA: m["A"].(string), NameB: m["B"].(string),471 NameC: m["C"].(string),472 Theta: theta, K: k,473 Comment: cmt}474 return angleType475}476func unpackTorsion(m map[string]interface{}) TorsionType {477 ttype, err := strconv.Atoi(m["type"].(string))478 if err != nil {479 log.Fatal(err)480 }481 n, err := strconv.Atoi(m["n"].(string))482 if err != nil {483 log.Fatal(err)484 }485 phi, err := strconv.ParseFloat(m["phi"].(string), 64)486 if err != nil {487 log.Fatal(err)488 }489 k, err := strconv.ParseFloat(m["k"].(string), 64)490 if err != nil {491 log.Fatal(err)492 }493 cmt, ok := m["comment"].(string)494 if !ok {495 cmt = ""496 }497 torsionType := TorsionType{498 NameA: m["A"].(string), NameB: m["B"].(string),499 NameC: m["C"].(string), NameD: m["D"].(string),500 Type: ttype, Phi: phi, N: n, K: k,501 Comment: cmt}502 return torsionType503}504func main() {505 jsonFile, err := os.Open("fosmmpl_complex.json")506 if err != nil {507 fmt.Println(err)508 }509 defer jsonFile.Close()510 byteValue, _ := ioutil.ReadAll(jsonFile)511 var dat map[string]interface{}512 if err := json.Unmarshal(byteValue, &dat); err != nil {513 log.Fatal(err)514 }515 var mmpl MMPL516 mmpl.Atoms = []Atom{}517 mmpl.Groups = []Group{}518 mmpl.Chains = []Chain{}519 mmpl.Molecules = []Molecule{}520 mmpl.BondTypes = []BondType{}521 mmpl.AngleTypes = []AngleType{}522 mmpl.TorsionTypes = []TorsionType{}523 // extract out the mmpl object and prepare to loop over the lists524 // within it525 mmplx := dat["mmpl"].(map[string]interface{})526 // atoms527 atoms := mmplx["atoms"]528 for k, v := range atoms.([]interface{}) {529 if mv, ok := v.(map[string]interface{}); ok {530 atom := unpackAtom(mv)531 mmpl.Atoms = append(mmpl.Atoms, atom)532 } else {533 log.Fatal("atoms was not a list", k, v)534 }535 }536 // groups537 groups := mmplx["groups"]538 for k, v := range groups.([]interface{}) {539 if mv, ok := v.(map[string]interface{}); ok {540 group := unpackGroup(mv)541 mmpl.Groups = append(mmpl.Groups, group)542 } else {543 log.Fatal("groups was not a list", k, v)544 }545 }546 // chains547 chains := mmplx["chains"]548 for k, v := range chains.([]interface{}) {549 if mv, ok := v.(map[string]interface{}); ok {550 chain := unpackChain(mv)551 mmpl.Chains = append(mmpl.Chains, chain)552 } else {553 log.Fatal("chains was not a list", k, v)554 }555 }556 // molecules557 molecules := mmplx["molecules"]558 for k, v := range molecules.([]interface{}) {559 if mv, ok := v.(map[string]interface{}); ok {560 molecule := unpackMolecule(mv)561 mmpl.Molecules = append(mmpl.Molecules, molecule)562 } else {563 log.Fatal("molecules was not a list", k, v)564 }565 }566 // bond types567 bonds := mmplx["bonds"]568 for k, v := range bonds.([]interface{}) {569 if mv, ok := v.(map[string]interface{}); ok {570 bondType := unpackBond(mv)571 mmpl.BondTypes = append(mmpl.BondTypes, bondType)572 } else {573 log.Fatal("bond element was not a list", k, v)574 }575 }576 // bond angle types577 angles := mmplx["angles"]578 for k, v := range angles.([]interface{}) {579 if mv, ok := v.(map[string]interface{}); ok {580 angleType := unpackAngle(mv)581 mmpl.AngleTypes = append(mmpl.AngleTypes, angleType)582 } else {583 log.Fatal("angle element was not a list", k, v)584 }585 }586 // torsion angle types587 torsions := mmplx["torsions"]588 for k, v := range torsions.([]interface{}) {589 if mv, ok := v.(map[string]interface{}); ok {590 torsionType := unpackTorsion(mv)591 mmpl.TorsionTypes = append(mmpl.TorsionTypes, torsionType)592 } else {593 log.Fatal("torsion element was not a list", k, v)594 }595 }596 json, err := json.MarshalIndent(mmpl, " ", " ")597 if err != nil {598 log.Fatal(err)599 }600 //fmt.Println(string(json))601 err = ioutil.WriteFile("fosmmpl.json", json, 0644)602 if err != nil {603 log.Fatal(err)604 }605}...
server_test.go
Source:server_test.go
1package jrpc2_2import (3 "bufio"4 "bytes"5 "encoding/json"6 "errors"7 "fmt"8 "net/http"9 "sync"10 "testing"11 "time"12)13type SumParams struct {14 X *float64 `json:"x"`15 Y *float64 `json:"y"`16}17func (ap *SumParams) FromPositional(params []interface{}) error {18 if len(params) != 2 {19 return errors.New(fmt.Sprintf("exactly two integers are required"))20 }21 x := params[0].(float64)22 y := params[1].(float64)23 ap.X = &x24 ap.Y = &y25 return nil26}27func Sum(params json.RawMessage) (interface{}, *ErrorObject) {28 p := new(SumParams)29 if err := ParseParams(params, p); err != nil {30 return nil, err31 }32 if p.X == nil || p.Y == nil {33 return nil, &ErrorObject{34 Code: InvalidParamsCode,35 Message: InvalidParamsMsg,36 Data: "exactly two integers are required",37 }38 }39 return *p.X + *p.Y, nil40}41type SubtractParams struct {42 X *float64 `json:"minuend"`43 Y *float64 `json:"subtrahend"`44}45func (ap *SubtractParams) FromPositional(params []interface{}) error {46 if len(params) != 2 {47 return errors.New(fmt.Sprintf("exactly two integers are required"))48 }49 x := params[0].(float64)50 y := params[1].(float64)51 ap.X = &x52 ap.Y = &y53 return nil54}55func Subtract(params json.RawMessage) (interface{}, *ErrorObject) {56 p := new(SubtractParams)57 if err := ParseParams(params, p); err != nil {58 return nil, err59 }60 if *p.X == 999.0 && *p.Y == 999.0 {61 return nil, &ErrorObject{62 Code: -32001,63 Message: ServerErrorMsg,64 Data: "Mock error",65 }66 }67 if p.X == nil || p.Y == nil {68 return nil, &ErrorObject{69 Code: InvalidParamsCode,70 Message: InvalidParamsMsg,71 Data: "exactly two integers are required",72 }73 }74 return *p.X - *p.Y, nil75}76func init() {77 var wg sync.WaitGroup78 wg.Add(1)79 go func() { // subtract method remote server80 s := NewServer(":31501", "/api/v2/rpc", nil)81 s.Register("subtract", Method{Method: Subtract})82 s.Start()83 }()84 go func() { // primary server with subtract remote server proxy85 s := NewServer(":31500", "/api/v1/rpc", map[string]string{86 "X-Test-Header": "some-test-value",87 })88 s.Register("sum", Method{Method: Sum})89 s.Register("update", Method{Method: func(params json.RawMessage) (interface{}, *ErrorObject) { return nil, nil }})90 s.Register("foobar", Method{Method: func(params json.RawMessage) (interface{}, *ErrorObject) { return nil, nil }})91 s.Start()92 }()93 go func() {94 for {95 body := `{"jsonrpc": "2.0", "method": "jrpc2.register", "params": ["subtract", "http://localhost:31501/api/v2/rpc"]}`96 buf := bytes.NewBuffer([]byte(body))97 _, err := http.Post("http://localhost:31500/api/v1/rpc", "application/json", buf)98 if err != nil {99 time.Sleep(1 * time.Second)100 continue101 }102 break103 }104 wg.Done()105 }()106 wg.Wait()107}108func TestResponseHeaders(t *testing.T) {109 buf := bytes.NewBuffer([]byte(`{}`))110 resp, err := http.Post("http://localhost:31500/api/v1/rpc", "application/json", buf)111 if err != nil {112 t.Fatal(err)113 }114 defer resp.Body.Close()115 if v := resp.Header.Get("X-Test-Header"); v != "some-test-value" {116 t.Fatal("got unexpected X-Test-Header value")117 }118}119func TestRpcCallWithPositionalParamters(t *testing.T) {120 table := []struct {121 Body string122 Jsonrpc string `json:"jsonrpc"`123 Result int `json:"result"`124 Id int `json:"id"`125 }{126 {`{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}`, "2.0", 19, 1},127 {`{"jsonrpc": "2.0", "method": "subtract", "params": [23, 42], "id": 2}`, "2.0", -19, 2},128 }129 for _, tc := range table {130 var result struct {131 Jsonrpc string `json:"jsonrpc"`132 Result int `json:"result"`133 Error interface{} `json:"error"`134 Id int `json:"id"`135 }136 buf := bytes.NewBuffer([]byte(tc.Body))137 resp, err := http.Post("http://localhost:31500/api/v1/rpc", "application/json", buf)138 if err != nil {139 t.Fatal(err)140 }141 rdr := bufio.NewReader(resp.Body)142 dec := json.NewDecoder(rdr)143 dec.Decode(&result)144 if result.Error != nil {145 t.Fatal("Expected error to be nil")146 }147 if result.Jsonrpc != tc.Jsonrpc {148 t.Fatal("Invalid jsonrpc member value")149 }150 if result.Result != tc.Result {151 t.Fatalf("Expected result to be %d", tc.Result)152 }153 if result.Id != tc.Id {154 t.Fatalf("Expected id to be %d", tc.Id)155 }156 }157}158func TestRpcCallWithPositionalParamtersError(t *testing.T) {159 var result struct {160 Jsonrpc string `json:"jsonrpc"`161 Result interface{} `json:"result"`162 Err ErrorObject `json:"error"`163 Id int `json:"id"`164 }165 body := `{"jsonrpc": "2.0", "method": "subtract", "params": [999, 999], "id": 1}`166 buf := bytes.NewBuffer([]byte(body))167 resp, err := http.Post("http://localhost:31500/api/v1/rpc", "application/json", buf)168 if err != nil {169 t.Fatal(err)170 }171 rdr := bufio.NewReader(resp.Body)172 dec := json.NewDecoder(rdr)173 dec.Decode(&result)174 if result.Result != nil {175 t.Fatal("Expected result to be nil")176 }177 if result.Err.Code != -32001 {178 t.Fatal("Expected code to be -32001")179 }180 if result.Err.Message != "Server error" {181 t.Fatal("Expected message to be 'Server error'")182 }183 if result.Err.Data != "Mock error" {184 t.Fatal("Expected data to be 'Mock error'")185 }186 if result.Id != 1 {187 t.Fatal("Expected id to be 1")188 }189}190func TestRpcCallWithNamedParameters(t *testing.T) {191 table := []struct {192 Body string193 Jsonrpc string `json:"jsonrpc"`194 Result int `json:"result"`195 Id int `json:"id"`196 }{197 {`{"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}`, "2.0", 19, 3},198 {`{"jsonrpc": "2.0", "method": "subtract", "params": {"minuend": 42, "subtrahend": 23}, "id": 4}`, "2.0", 19, 4},199 }200 for _, tc := range table {201 var result struct {202 Jsonrpc string `json:"jsonrpc"`203 Result int `json:"result"`204 Error interface{} `json:"error"`205 Id int `json:"id"`206 }207 buf := bytes.NewBuffer([]byte(tc.Body))208 resp, err := http.Post("http://localhost:31500/api/v1/rpc", "application/json", buf)209 if err != nil {210 t.Fatal(err)211 }212 rdr := bufio.NewReader(resp.Body)213 dec := json.NewDecoder(rdr)214 dec.Decode(&result)215 if result.Error != nil {216 t.Fatal("Expected error to be nil")217 }218 if result.Jsonrpc != tc.Jsonrpc {219 t.Fatal("Invalid jsonrpc member value")220 }221 if result.Result != tc.Result {222 t.Fatalf("Expected result to be %d", tc.Result)223 }224 if result.Id != tc.Id {225 t.Fatalf("Expected id to be %d", tc.Id)226 }227 }228}229func TestNotification(t *testing.T) {230 table := []string{231 `{"jsonrpc": "2.0", "method": "update", "params": [1,2,3,4,5]}`,232 `{"jsonrpc": "2.0", "method": "foobar"}`,233 }234 for _, body := range table {235 buf := bytes.NewBuffer([]byte(body))236 resp, err := http.Post("http://localhost:31500/api/v1/rpc", "application/json", buf)237 if err != nil {238 t.Fatal(err)239 }240 rdr := bufio.NewReader(resp.Body)241 data, err := rdr.ReadBytes('\b')242 if len(data) > 0 {243 t.Fatal("Expected notification to return no response body")244 }245 }246}247func TestCallOfNotExistentMethod(t *testing.T) {248 var result struct {249 Jsonrpc string `json:"jsonrpc"`250 Err ErrorObject `json:"error"`251 Result interface{} `json:"result"`252 Id int `json:"id"`253 }254 body := `{"jsonrpc": "2.0", "method": "fooba", "id": "1"}`255 buf := bytes.NewBuffer([]byte(body))256 resp, err := http.Post("http://localhost:31500/api/v1/rpc", "application/json", buf)257 if err != nil {258 t.Fatal(err)259 }260 rdr := bufio.NewReader(resp.Body)261 dec := json.NewDecoder(rdr)262 dec.Decode(&result)263 if result.Result != nil {264 t.Fatal("expected result to be nil")265 }266 if result.Err.Code != -32601 {267 t.Fatal("expected error code -32601")268 }269 if result.Err.Message != "Method not found" {270 t.Fatal("expected message to be 'Message not found'")271 }272}273func TestCallWithInvalidJSON(t *testing.T) {274 var result struct {275 Jsonrpc string `json:"jsonrpc"`276 Err ErrorObject `json:"error"`277 Result interface{} `json:"result"`278 Id int `json:"id"`279 }280 body := `{"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz]`281 buf := bytes.NewBuffer([]byte(body))282 resp, err := http.Post("http://localhost:31500/api/v1/rpc", "application/json", buf)283 if err != nil {284 t.Fatal(err)285 }286 rdr := bufio.NewReader(resp.Body)287 dec := json.NewDecoder(rdr)288 dec.Decode(&result)289 if result.Result != nil {290 t.Fatal("expected result to be nil")291 }292 if result.Err.Code != -32700 {293 t.Fatal("expected error code -32700")294 }295 if result.Err.Message != "Parse error" {296 t.Fatal("expected message to be 'Parse error'")297 }298}299func TestCallWithInvalidRequestObject(t *testing.T) {300 var result struct {301 Jsonrpc string `json:"jsonrpc"`302 Err ErrorObject `json:"error"`303 Result interface{} `json:"result"`304 Id int `json:"id"`305 }306 body := `{"jsonrpc": "2.0", "method": 1, "params": "bar"}`307 buf := bytes.NewBuffer([]byte(body))308 resp, err := http.Post("http://localhost:31500/api/v1/rpc", "application/json", buf)309 if err != nil {310 t.Fatal(err)311 }312 rdr := bufio.NewReader(resp.Body)313 dec := json.NewDecoder(rdr)314 dec.Decode(&result)315 if result.Result != nil {316 t.Fatal("expected result to be nil")317 }318 if result.Err.Code != -32600 {319 t.Fatal("expected error code -32600")320 }321 if result.Err.Message != "Invalid Request" {322 t.Fatal("expected message to be 'Invalid Request'")323 }324}325func TestBatchCallWithInvalidJSON(t *testing.T) {326 var result struct {327 Jsonrpc string `json:"jsonrpc"`328 Err ErrorObject `json:"error"`329 Result interface{} `json:"result"`330 Id int `json:"id"`331 }332 body := `[333 {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},334 {"jsonrpc": "2.0", "method"335 ]`336 buf := bytes.NewBuffer([]byte(body))337 resp, err := http.Post("http://localhost:31500/api/v1/rpc", "application/json", buf)338 if err != nil {339 t.Fatal(err)340 }341 rdr := bufio.NewReader(resp.Body)342 dec := json.NewDecoder(rdr)343 dec.Decode(&result)344 if result.Result != nil {345 t.Fatal("expected result to be nil")346 }347 if result.Err.Code != -32700 {348 t.Fatal("expected error code -32700")349 }350 if result.Err.Message != "Parse error" {351 t.Fatal("expected message to be 'Parse error'")352 }353}354func TestBatchCallWithAnEmptyArray(t *testing.T) {355 var result struct {356 Jsonrpc string `json:"jsonrpc"`357 Err ErrorObject `json:"error"`358 Result interface{} `json:"result"`359 Id int `json:"id"`360 }361 body := `[]`362 buf := bytes.NewBuffer([]byte(body))363 resp, err := http.Post("http://localhost:31500/api/v1/rpc", "application/json", buf)364 if err != nil {365 t.Fatal(err)366 }367 rdr := bufio.NewReader(resp.Body)368 dec := json.NewDecoder(rdr)369 dec.Decode(&result)370 if result.Result != nil {371 t.Fatal("expected result to be nil")372 }373 if result.Err.Code != -32600 {374 t.Fatal("expected error code -32600")375 }376 if result.Err.Message != "Invalid Request" {377 t.Fatal("expected message to be 'Invalid Request'")378 }379}380func TestCallWithAnInvalidBatch(t *testing.T) {381 var results []struct {382 Jsonrpc string `json:"jsonrpc"`383 Err ErrorObject `json:"error"`384 Result interface{} `json:"result"`385 Id int `json:"id"`386 }387 body := `[]`388 buf := bytes.NewBuffer([]byte(body))389 resp, err := http.Post("http://localhost:31500/api/v1/rpc", "application/json", buf)390 if err != nil {391 t.Fatal(err)392 }393 rdr := bufio.NewReader(resp.Body)394 dec := json.NewDecoder(rdr)395 dec.Decode(&results)396 for _, result := range results {397 if result.Result != nil {398 t.Fatal("expected result to be nil")399 }400 if result.Err.Code != -32600 {401 t.Fatal("expected error code -32600")402 }403 if result.Err.Message != "Invalid Request" {404 t.Fatal("expected message to be 'Invalid Request'")405 }406 }407}408func TestCallBatchWithNotifications(t *testing.T) {409 body := `[410 {"jsonrpc": "2.0", "method": "sum", "params": [1,2]},411 {"jsonrpc": "2.0", "method": "subtract", "params": [7,2]}412 ]`413 buf := bytes.NewBuffer([]byte(body))414 resp, err := http.Post("http://localhost:31500/api/v1/rpc", "application/json", buf)415 if err != nil {416 t.Fatal(err)417 }418 rdr := bufio.NewReader(resp.Body)419 data, err := rdr.ReadBytes('\n')420 if len(data) > 0 {421 t.Fatal("Expected batch notification to return no response body")422 }423}...
configurator_test.go
Source:configurator_test.go
1// Copyright 2020 The ZKits Project Authors.2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7// http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.14package configurator15import (16 "errors"17 "testing"18)19func TestNew(t *testing.T) {20 o := New()21 if o == nil {22 t.Fatal("New(): nil")23 }24}25func TestConfigurator(t *testing.T) {26 o := New()27 l := NewFileLoader()28 if err := o.AddFile("test/*"); err != nil {29 t.Fatal(err)30 }31 o.Use(l)32 do := func(fs ...func(Configurator)) {33 for _, f := range fs {34 f(o)35 }36 }37 type Value struct {38 Name string `json:"name" xml:"name" toml:"name" yaml:"name"`39 }40 do(func(c Configurator) {41 item, err := c.Load("test.txt")42 if err != nil {43 t.Fatalf("Configurator.Load(): %s", err)44 }45 if got := item.String(); got != "test" {46 t.Fatalf("Configurator.Load(): %s", got)47 }48 if item, err := c.Load("unknown"); err == nil {49 t.Fatalf("Configurator.Load(): no error")50 } else {51 if err != ErrNotFound {52 t.Fatalf("Configurator.Load(): %s", err)53 }54 if item != nil {55 t.Fatalf("Configurator.Load(): %v", item)56 }57 }58 }, func(c Configurator) {59 v := new(Value)60 if err := c.LoadJSON("test.json", v); err != nil {61 t.Fatalf("Configurator.LoadJSON(): %s", err)62 }63 if v.Name != "test" {64 t.Fatalf("Configurator.LoadJSON(): %s", v.Name)65 }66 v = new(Value)67 if err := c.LoadJSON("unknown.json", v); err == nil {68 t.Fatalf("Configurator.LoadJSON(): no error")69 } else {70 if err != ErrNotFound {71 t.Fatalf("Configurator.LoadJSON(): %s", err)72 }73 }74 if v.Name != "" {75 t.Fatalf("Configurator.LoadJSON(): %s", v.Name)76 }77 }, func(c Configurator) {78 v := new(Value)79 if err := c.LoadXML("test.xml", v); err != nil {80 t.Fatalf("Configurator.LoadXML(): %s", err)81 }82 if v.Name != "test" {83 t.Fatalf("Configurator.LoadXML(): %s", v.Name)84 }85 v = new(Value)86 if err := c.LoadXML("unknown.xml", v); err == nil {87 t.Fatalf("Configurator.LoadXML(): no error")88 } else {89 if err != ErrNotFound {90 t.Fatalf("Configurator.LoadXML(): %s", err)91 }92 }93 if v.Name != "" {94 t.Fatalf("Configurator.LoadXML(): %s", v.Name)95 }96 }, func(c Configurator) {97 v := new(Value)98 if err := c.LoadTOML("test.toml", v); err != nil {99 t.Fatalf("Configurator.LoadTOML(): %s", err)100 }101 if v.Name != "test" {102 t.Fatalf("Configurator.LoadTOML(): %s", v.Name)103 }104 v = new(Value)105 if err := c.LoadTOML("unknown.toml", v); err == nil {106 t.Fatalf("Configurator.LoadTOML(): no error")107 } else {108 if err != ErrNotFound {109 t.Fatalf("Configurator.LoadTOML(): %s", err)110 }111 }112 if v.Name != "" {113 t.Fatalf("Configurator.LoadTOML(): %s", v.Name)114 }115 }, func(c Configurator) {116 v := new(Value)117 if err := c.LoadYAML("test.yaml", v); err != nil {118 t.Fatalf("Configurator.LoadYAML(): %s", err)119 }120 if v.Name != "test" {121 t.Fatalf("Configurator.LoadYAML(): %s", v.Name)122 }123 v = new(Value)124 if err := c.LoadYAML("unknown.yaml", v); err == nil {125 t.Fatalf("Configurator.LoadYAML(): no error")126 } else {127 if err != ErrNotFound {128 t.Fatalf("Configurator.LoadYAML(): %s", err)129 }130 }131 if v.Name != "" {132 t.Fatalf("Configurator.LoadYAML(): %s", v.Name)133 }134 })135}136func TestConfiguratorLoadError(t *testing.T) {137 o := New()138 o.Use(LoaderFunc(func(string) (Item, error) {139 return nil, errors.New("test")140 }))141 item, err := o.Load("test")142 if err == nil {143 t.Fatal("nil error")144 }145 if item != nil {146 t.Fatal(item)147 }148}149func TestConfiguratorLoad(t *testing.T) {150 o := New()151 if err := o.AddFile("test/foo/*"); err != nil {152 t.Fatal(err)153 }154 type Value struct {155 Name string `json:"name"`156 }157 do := func(fs ...func()) {158 for _, f := range fs {159 f()160 }161 }162 do(func() {163 v := new(Value)164 if err := o.LoadJSON("a", v); err != nil {165 t.Fatal(err)166 }167 if v.Name != "a.json" {168 t.Fatal(v.Name)169 }170 }, func() {171 v := new(Value)172 if err := o.LoadJSON("a.json", v); err != nil {173 t.Fatal(err)174 }175 if v.Name != "a.json" {176 t.Fatal(v.Name)177 }178 }, func() {179 v := new(Value)180 if err := o.LoadJSON("b", v); err != nil {181 t.Fatal(err)182 }183 if v.Name != "b.json" {184 t.Fatal(v.Name)185 }186 }, func() {187 v := new(Value)188 if err := o.LoadJSON("b.json", v); err != nil {189 t.Fatal(err)190 }191 if v.Name != "b.json" {192 t.Fatal(v.Name)193 }194 })195 o.Use(NewFileLoader().MustAddFile("test/bar/*"))196 do(func() {197 v := new(Value)198 if err := o.LoadJSON("a", v); err != nil {199 t.Fatal(err)200 }201 if v.Name != "bar" {202 t.Fatal(v.Name)203 }204 }, func() {205 v := new(Value)206 if err := o.LoadJSON("a.json", v); err != nil {207 t.Fatal(err)208 }209 if v.Name != "bar" {210 t.Fatal(v.Name)211 }212 }, func() {213 v := new(Value)214 if err := o.LoadJSON("b", v); err != nil {215 t.Fatal(err)216 }217 if v.Name != "b.json" {218 t.Fatal(v.Name)219 }220 }, func() {221 v := new(Value)222 if err := o.LoadJSON("b.json", v); err != nil {223 t.Fatal(err)224 }225 if v.Name != "b.json" {226 t.Fatal(v.Name)227 }228 })229 if _, err := o.Load("a.xml"); err != ErrNotFound {230 t.Fatal(err)231 }232}...
fatal
Using AI Code Generation
1import (2type Response1 struct {3}4func main() {5 bolB, _ := json.Marshal(true)6 fmt.Println(string(bolB))7 intB, _ := json.Marshal(1)8 fmt.Println(string(intB))9 fltB, _ := json.Marshal(2.34)10 fmt.Println(string(fltB))11 strB, _ := json.Marshal("gopher")12 fmt.Println(string(strB))13 slcD := []string{"apple", "peach", "pear"}14 slcB, _ := json.Marshal(slcD)15 fmt.Println(string(slcB))16 mapD := map[string]int{"apple": 5, "lettuce": 7}17 mapB, _ := json.Marshal(mapD)18 fmt.Println(string(mapB))19 res1D := &Response1{20 Fruits: []string{"apple", "peach", "pear"}}21 res1B, _ := json.Marshal(res1D)22 fmt.Println(string(res1B))23 byt := []byte(`{"num":6.13,"strs":["a","b"]}`)24 var dat map[string]interface{}25 if err := json.Unmarshal(byt, &dat); err != nil {26 panic(err)27 }28 fmt.Println(dat)29 num := dat["num"].(float64)30 fmt.Println(num)31 strs := dat["strs"].([]interface{})32 str1 := strs[0].(string)33 fmt.Println(str1)34 str := `{"page": 1, "fruits": ["apple", "peach"]}`35 res := Response1{}36 json.Unmarshal([]byte(str), &res)37 fmt.Println(res)38 fmt.Println(res.Fruits[0])39 enc := json.NewEncoder(os.Stdout)40 d := map[string]int{"apple": 5, "lettuce": 7}41 enc.Encode(d)42}43{"apple":5,"lettuce":7}44{"Page":1,"Fruits":["apple","peach","pear"]}45{1 [apple peach]}46{"apple":5,"lettuce":7}
fatal
Using AI Code Generation
1import (2func main() {3 var jsonBlob = []byte(`[4 {"Name": "Platypus", "Order": "Monotremata"},5 {"Name": "Quoll", "Order": "Dasyuromorphia"}6 type Animal struct {7 }8 err := json.Unmarshal(jsonBlob, &animals)9 if err != nil {10 fmt.Println("error:", err)11 }12 fmt.Printf("%+v", animals)13}14[{"Name":"Platypus","Order":"Monotremata"},{"Name":"Quoll","Order":"Dasyuromorphia"}]
fatal
Using AI Code Generation
1import (2type Person struct {3}4func main() {5 p1 := Person{"James", "Bond", 20}6 bs, _ := json.Marshal(p1)7 fmt.Println(bs)8 fmt.Printf("%T \n", bs)9 fmt.Println(string(bs))10}11import (12type Person struct {13}14func main() {15 p1 := Person{"James", "Bond", 20}16 bs, _ := json.Marshal(p1)17 fmt.Println(bs)18 fmt.Printf("%T \n", bs)19 fmt.Println(string(bs))20}21import (22type Person struct {23}24func main() {25 p1 := Person{"James", "Bond", 20}26 bs, _ := json.Marshal(p1)27 fmt.Println(bs)28 fmt.Printf("%T \n", bs)29 fmt.Println(string(bs))30}
fatal
Using AI Code Generation
1import (2func main() {3 var jsonBlob = []byte(`[4 {"Name": "Platypus", "Order": "Monotremata"},5 {"Name": "Quoll", "Order": "Dasyuromorphia"}6 type Animal struct {7 }8 err := json.Unmarshal(jsonBlob, &animals)9 if err != nil {10 fmt.Println("error:", err)11 }12 fmt.Printf("%+v", animals)13}14[{"Name":"Platypus","Order":"Monotremata"},{"Name":"Quoll","Order":"Dasyuromorphia"}]15import (16func main() {17 var jsonBlob = []byte(`[18 {"Name": "Platypus", "Order": "Monotremata"},19 {"Name": "Quoll", "Order": "Dasyuromorphia"}20 type Animal struct {21 }22 err := json.Unmarshal(jsonBlob, &animals)23 if err != nil {24 fmt.Println("error:", err)25 }26 fmt.Printf("%+v", animals)27}28[{"Name":"Platypus","Order":"Monotremata"},{"Name":"Quoll","Order":"Dasyuromorphia"}]
fatal
Using AI Code Generation
1import (2func main() {3 var jsonBlob = []byte(`[4 {"Name": "Platypus", "Order": "Monotremata"},5 {"Name": "Quoll", "Order": "Dasyuromorphia"}6 type Animal struct {7 }8 err := json.Unmarshal(jsonBlob, &animals)9 if err != nil {10 log.Fatal(err)11 }12 fmt.Printf("%+v13}14import (15func main() {16 var jsonBlob = []byte(`[17 {"Name": "Platypus", "Order": "Monotremata"},18 {"Name": "Quoll", "Order": "Dasyuromorphia"}19 type Animal struct {20 }21 err := json.Unmarshal(jsonBlob, &animals)22 if err != nil {23 log.Panic(err)24 }25 fmt.Printf("%+v26}27import (28func main() {29 var jsonBlob = []byte(`[30 {"Name": "Platypus", "Order": "Monotremata"},31 {"Name": "Quoll", "Order": "Dasyuromorphia"}32 type Animal struct {33 }34 err := json.Unmarshal(jsonBlob, &animals)35 if err != nil {36 log.Print(err)37 }38 fmt.Printf("%+v39}40import (41func main() {42 var jsonBlob = []byte(`[43 {"Name": "Platypus", "Order": "Monotremata"},44 {"Name": "Quoll", "Order": "Dasyuromorphia"}
fatal
Using AI Code Generation
1import (2type Response1 struct {3}4func main() {5 var dat map[string]interface{}6 enc := json.NewEncoder(os.Stdout)7 d := map[string]int{"apple": 5, "lettuce": 7}8 enc.Encode(d)9}
fatal
Using AI Code Generation
1import (2type Person struct {3}4func main() {5 person := &Person{Name: "John", Age: 30}6 encoder := json.NewEncoder(os.Stdout)7 encoder.SetIndent("", " ")8 err := encoder.Encode(person)9 if err != nil {10 fmt.Println("Error:", err)11 }12}13{14}15import (16type Person struct {17}18func main() {19 person := &Person{Name: "John", Age: 30}20 encoder := json.NewEncoder(os.Stdout)21 encoder.SetIndent("", " ")22 err := encoder.Encode(person)23 if err != nil {24 fmt.Println("Error:", err)25 }26}27{28}29import (30type Person struct {31}32func main() {33 person := &Person{Name: "John", Age: 30}34 encoder := json.NewEncoder(os.Stdout)35 encoder.SetIndent("", " ")36 err := encoder.Encode(person)37 if err != nil {38 fmt.Println("Error:", err)39 }40}41{42}43import (44type Person struct {45}46func main() {47 person := &Person{Name: "John", Age: 30}48 encoder := json.NewEncoder(os.Stdout)49 encoder.SetIndent("", " ")50 err := encoder.Encode(person)51 if err != nil {52 fmt.Println("Error:", err)53 }54}55{56}57import (
fatal
Using AI Code Generation
1import (2func main() {3 type Employee struct {4 }5 data, err := json.Marshal(emp)6 if err != nil {7 fmt.Println("error:", err)8 }9 fmt.Println(string(data))10}11{"Name":"John","Age":34}12Example 3: Using MarshalIndent() method13import (14func main() {15 type Employee struct {16 }17 data, err := json.MarshalIndent(emp, "", " ")18 if err != nil {19 fmt.Println("error:", err)20 }21 fmt.Println(string(data))22}23{24}25Example 4: Using Unmarshal() method26import (27func main() {28 type Employee struct {29 }30 data, err := json.Marshal(emp)31 if err != nil {32 fmt.Println("error:", err)33 }34 fmt.Println(string(data))35 json.Unmarshal(data, &emp1)36 fmt.Println(emp1.Name)37 fmt.Println(emp1.Age)38}39{"Name":"John","Age":34}40Example 5: Using NewDecoder() method41import (42func main() {43 type Employee struct {44 }45 data, err := json.Marshal(emp)46 if err != nil {47 fmt.Println("error:", err)
fatal
Using AI Code Generation
1import (2func main() {3 fmt.Println("Enter your name")4 fmt.Scanln(&name)5 e := json.NewDecoder(os.Stdin)6 err := e.Decode(&m)7 if err != nil {8 log.Fatal(err)9 }10 fmt.Println("Map is: ", m)11}
fatal
Using AI Code Generation
1import (2func main() {3 data := []byte(`{"Name":"John","Age":30,"City":"New York"}`)4 var result map[string]interface{}5 err := json.Unmarshal(data, &result)6 if err != nil {7 log.Fatal(err)8 }9 log.Println(result)10}11import (12func main() {13 data := []byte(`{"Name":"John","Age":30,"City":"New York"}`)14 var result map[string]interface{}15 err := json.Unmarshal(data, &result)16 if err != nil {17 log.Panic(err)18 }19 log.Println(result)20}21main.main()22import (23func main() {24 data := []byte(`{"Name":"John","Age":30,"City":"New York"}`)25 var result map[string]interface{}26 err := json.Unmarshal(data, &result)27 if err != nil {28 panic(err)29 }30 log.Println(result)31}
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!