override_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. package common
  2. import (
  3. "encoding/json"
  4. "reflect"
  5. "testing"
  6. )
  7. func TestApplyParamOverrideTrimPrefix(t *testing.T) {
  8. // trim_prefix example:
  9. // {"operations":[{"path":"model","mode":"trim_prefix","value":"openai/"}]}
  10. input := []byte(`{"model":"openai/gpt-4","temperature":0.7}`)
  11. override := map[string]interface{}{
  12. "operations": []interface{}{
  13. map[string]interface{}{
  14. "path": "model",
  15. "mode": "trim_prefix",
  16. "value": "openai/",
  17. },
  18. },
  19. }
  20. out, err := ApplyParamOverride(input, override, nil)
  21. if err != nil {
  22. t.Fatalf("ApplyParamOverride returned error: %v", err)
  23. }
  24. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
  25. }
  26. func TestApplyParamOverrideTrimSuffix(t *testing.T) {
  27. // trim_suffix example:
  28. // {"operations":[{"path":"model","mode":"trim_suffix","value":"-latest"}]}
  29. input := []byte(`{"model":"gpt-4-latest","temperature":0.7}`)
  30. override := map[string]interface{}{
  31. "operations": []interface{}{
  32. map[string]interface{}{
  33. "path": "model",
  34. "mode": "trim_suffix",
  35. "value": "-latest",
  36. },
  37. },
  38. }
  39. out, err := ApplyParamOverride(input, override, nil)
  40. if err != nil {
  41. t.Fatalf("ApplyParamOverride returned error: %v", err)
  42. }
  43. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
  44. }
  45. func TestApplyParamOverrideTrimNoop(t *testing.T) {
  46. // trim_prefix no-op example:
  47. // {"operations":[{"path":"model","mode":"trim_prefix","value":"openai/"}]}
  48. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  49. override := map[string]interface{}{
  50. "operations": []interface{}{
  51. map[string]interface{}{
  52. "path": "model",
  53. "mode": "trim_prefix",
  54. "value": "openai/",
  55. },
  56. },
  57. }
  58. out, err := ApplyParamOverride(input, override, nil)
  59. if err != nil {
  60. t.Fatalf("ApplyParamOverride returned error: %v", err)
  61. }
  62. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
  63. }
  64. func TestApplyParamOverrideTrimRequiresValue(t *testing.T) {
  65. // trim_prefix requires value example:
  66. // {"operations":[{"path":"model","mode":"trim_prefix"}]}
  67. input := []byte(`{"model":"gpt-4"}`)
  68. override := map[string]interface{}{
  69. "operations": []interface{}{
  70. map[string]interface{}{
  71. "path": "model",
  72. "mode": "trim_prefix",
  73. },
  74. },
  75. }
  76. _, err := ApplyParamOverride(input, override, nil)
  77. if err == nil {
  78. t.Fatalf("expected error, got nil")
  79. }
  80. }
  81. func TestApplyParamOverrideReplace(t *testing.T) {
  82. // replace example:
  83. // {"operations":[{"path":"model","mode":"replace","from":"openai/","to":""}]}
  84. input := []byte(`{"model":"openai/gpt-4o-mini","temperature":0.7}`)
  85. override := map[string]interface{}{
  86. "operations": []interface{}{
  87. map[string]interface{}{
  88. "path": "model",
  89. "mode": "replace",
  90. "from": "openai/",
  91. "to": "",
  92. },
  93. },
  94. }
  95. out, err := ApplyParamOverride(input, override, nil)
  96. if err != nil {
  97. t.Fatalf("ApplyParamOverride returned error: %v", err)
  98. }
  99. assertJSONEqual(t, `{"model":"gpt-4o-mini","temperature":0.7}`, string(out))
  100. }
  101. func TestApplyParamOverrideRegexReplace(t *testing.T) {
  102. // regex_replace example:
  103. // {"operations":[{"path":"model","mode":"regex_replace","from":"^gpt-","to":"openai/gpt-"}]}
  104. input := []byte(`{"model":"gpt-4o-mini","temperature":0.7}`)
  105. override := map[string]interface{}{
  106. "operations": []interface{}{
  107. map[string]interface{}{
  108. "path": "model",
  109. "mode": "regex_replace",
  110. "from": "^gpt-",
  111. "to": "openai/gpt-",
  112. },
  113. },
  114. }
  115. out, err := ApplyParamOverride(input, override, nil)
  116. if err != nil {
  117. t.Fatalf("ApplyParamOverride returned error: %v", err)
  118. }
  119. assertJSONEqual(t, `{"model":"openai/gpt-4o-mini","temperature":0.7}`, string(out))
  120. }
  121. func TestApplyParamOverrideReplaceRequiresFrom(t *testing.T) {
  122. // replace requires from example:
  123. // {"operations":[{"path":"model","mode":"replace"}]}
  124. input := []byte(`{"model":"gpt-4"}`)
  125. override := map[string]interface{}{
  126. "operations": []interface{}{
  127. map[string]interface{}{
  128. "path": "model",
  129. "mode": "replace",
  130. },
  131. },
  132. }
  133. _, err := ApplyParamOverride(input, override, nil)
  134. if err == nil {
  135. t.Fatalf("expected error, got nil")
  136. }
  137. }
  138. func TestApplyParamOverrideRegexReplaceRequiresPattern(t *testing.T) {
  139. // regex_replace requires from(pattern) example:
  140. // {"operations":[{"path":"model","mode":"regex_replace"}]}
  141. input := []byte(`{"model":"gpt-4"}`)
  142. override := map[string]interface{}{
  143. "operations": []interface{}{
  144. map[string]interface{}{
  145. "path": "model",
  146. "mode": "regex_replace",
  147. },
  148. },
  149. }
  150. _, err := ApplyParamOverride(input, override, nil)
  151. if err == nil {
  152. t.Fatalf("expected error, got nil")
  153. }
  154. }
  155. func TestApplyParamOverrideDelete(t *testing.T) {
  156. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  157. override := map[string]interface{}{
  158. "operations": []interface{}{
  159. map[string]interface{}{
  160. "path": "temperature",
  161. "mode": "delete",
  162. },
  163. },
  164. }
  165. out, err := ApplyParamOverride(input, override, nil)
  166. if err != nil {
  167. t.Fatalf("ApplyParamOverride returned error: %v", err)
  168. }
  169. var got map[string]interface{}
  170. if err := json.Unmarshal(out, &got); err != nil {
  171. t.Fatalf("failed to unmarshal output JSON: %v", err)
  172. }
  173. if _, exists := got["temperature"]; exists {
  174. t.Fatalf("expected temperature to be deleted")
  175. }
  176. }
  177. func TestApplyParamOverrideSet(t *testing.T) {
  178. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  179. override := map[string]interface{}{
  180. "operations": []interface{}{
  181. map[string]interface{}{
  182. "path": "temperature",
  183. "mode": "set",
  184. "value": 0.1,
  185. },
  186. },
  187. }
  188. out, err := ApplyParamOverride(input, override, nil)
  189. if err != nil {
  190. t.Fatalf("ApplyParamOverride returned error: %v", err)
  191. }
  192. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.1}`, string(out))
  193. }
  194. func TestApplyParamOverrideSetKeepOrigin(t *testing.T) {
  195. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  196. override := map[string]interface{}{
  197. "operations": []interface{}{
  198. map[string]interface{}{
  199. "path": "temperature",
  200. "mode": "set",
  201. "value": 0.1,
  202. "keep_origin": true,
  203. },
  204. },
  205. }
  206. out, err := ApplyParamOverride(input, override, nil)
  207. if err != nil {
  208. t.Fatalf("ApplyParamOverride returned error: %v", err)
  209. }
  210. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
  211. }
  212. func TestApplyParamOverrideMove(t *testing.T) {
  213. input := []byte(`{"model":"gpt-4","meta":{"x":1}}`)
  214. override := map[string]interface{}{
  215. "operations": []interface{}{
  216. map[string]interface{}{
  217. "mode": "move",
  218. "from": "model",
  219. "to": "meta.model",
  220. },
  221. },
  222. }
  223. out, err := ApplyParamOverride(input, override, nil)
  224. if err != nil {
  225. t.Fatalf("ApplyParamOverride returned error: %v", err)
  226. }
  227. assertJSONEqual(t, `{"meta":{"x":1,"model":"gpt-4"}}`, string(out))
  228. }
  229. func TestApplyParamOverrideMoveMissingSource(t *testing.T) {
  230. input := []byte(`{"meta":{"x":1}}`)
  231. override := map[string]interface{}{
  232. "operations": []interface{}{
  233. map[string]interface{}{
  234. "mode": "move",
  235. "from": "model",
  236. "to": "meta.model",
  237. },
  238. },
  239. }
  240. _, err := ApplyParamOverride(input, override, nil)
  241. if err == nil {
  242. t.Fatalf("expected error, got nil")
  243. }
  244. }
  245. func TestApplyParamOverridePrependAppendString(t *testing.T) {
  246. input := []byte(`{"model":"gpt-4"}`)
  247. override := map[string]interface{}{
  248. "operations": []interface{}{
  249. map[string]interface{}{
  250. "path": "model",
  251. "mode": "prepend",
  252. "value": "openai/",
  253. },
  254. map[string]interface{}{
  255. "path": "model",
  256. "mode": "append",
  257. "value": "-latest",
  258. },
  259. },
  260. }
  261. out, err := ApplyParamOverride(input, override, nil)
  262. if err != nil {
  263. t.Fatalf("ApplyParamOverride returned error: %v", err)
  264. }
  265. assertJSONEqual(t, `{"model":"openai/gpt-4-latest"}`, string(out))
  266. }
  267. func TestApplyParamOverridePrependAppendArray(t *testing.T) {
  268. input := []byte(`{"arr":[1,2]}`)
  269. override := map[string]interface{}{
  270. "operations": []interface{}{
  271. map[string]interface{}{
  272. "path": "arr",
  273. "mode": "prepend",
  274. "value": 0,
  275. },
  276. map[string]interface{}{
  277. "path": "arr",
  278. "mode": "append",
  279. "value": []interface{}{3, 4},
  280. },
  281. },
  282. }
  283. out, err := ApplyParamOverride(input, override, nil)
  284. if err != nil {
  285. t.Fatalf("ApplyParamOverride returned error: %v", err)
  286. }
  287. assertJSONEqual(t, `{"arr":[0,1,2,3,4]}`, string(out))
  288. }
  289. func TestApplyParamOverrideAppendObjectMergeKeepOrigin(t *testing.T) {
  290. input := []byte(`{"obj":{"a":1}}`)
  291. override := map[string]interface{}{
  292. "operations": []interface{}{
  293. map[string]interface{}{
  294. "path": "obj",
  295. "mode": "append",
  296. "keep_origin": true,
  297. "value": map[string]interface{}{
  298. "a": 2,
  299. "b": 3,
  300. },
  301. },
  302. },
  303. }
  304. out, err := ApplyParamOverride(input, override, nil)
  305. if err != nil {
  306. t.Fatalf("ApplyParamOverride returned error: %v", err)
  307. }
  308. assertJSONEqual(t, `{"obj":{"a":1,"b":3}}`, string(out))
  309. }
  310. func TestApplyParamOverrideAppendObjectMergeOverride(t *testing.T) {
  311. input := []byte(`{"obj":{"a":1}}`)
  312. override := map[string]interface{}{
  313. "operations": []interface{}{
  314. map[string]interface{}{
  315. "path": "obj",
  316. "mode": "append",
  317. "value": map[string]interface{}{
  318. "a": 2,
  319. "b": 3,
  320. },
  321. },
  322. },
  323. }
  324. out, err := ApplyParamOverride(input, override, nil)
  325. if err != nil {
  326. t.Fatalf("ApplyParamOverride returned error: %v", err)
  327. }
  328. assertJSONEqual(t, `{"obj":{"a":2,"b":3}}`, string(out))
  329. }
  330. func TestApplyParamOverrideConditionORDefault(t *testing.T) {
  331. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  332. override := map[string]interface{}{
  333. "operations": []interface{}{
  334. map[string]interface{}{
  335. "path": "temperature",
  336. "mode": "set",
  337. "value": 0.1,
  338. "conditions": []interface{}{
  339. map[string]interface{}{
  340. "path": "model",
  341. "mode": "prefix",
  342. "value": "gpt",
  343. },
  344. map[string]interface{}{
  345. "path": "model",
  346. "mode": "prefix",
  347. "value": "claude",
  348. },
  349. },
  350. },
  351. },
  352. }
  353. out, err := ApplyParamOverride(input, override, nil)
  354. if err != nil {
  355. t.Fatalf("ApplyParamOverride returned error: %v", err)
  356. }
  357. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.1}`, string(out))
  358. }
  359. func TestApplyParamOverrideConditionAND(t *testing.T) {
  360. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  361. override := map[string]interface{}{
  362. "operations": []interface{}{
  363. map[string]interface{}{
  364. "path": "temperature",
  365. "mode": "set",
  366. "value": 0.1,
  367. "logic": "AND",
  368. "conditions": []interface{}{
  369. map[string]interface{}{
  370. "path": "model",
  371. "mode": "prefix",
  372. "value": "gpt",
  373. },
  374. map[string]interface{}{
  375. "path": "temperature",
  376. "mode": "gt",
  377. "value": 0.5,
  378. },
  379. },
  380. },
  381. },
  382. }
  383. out, err := ApplyParamOverride(input, override, nil)
  384. if err != nil {
  385. t.Fatalf("ApplyParamOverride returned error: %v", err)
  386. }
  387. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.1}`, string(out))
  388. }
  389. func TestApplyParamOverrideConditionInvert(t *testing.T) {
  390. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  391. override := map[string]interface{}{
  392. "operations": []interface{}{
  393. map[string]interface{}{
  394. "path": "temperature",
  395. "mode": "set",
  396. "value": 0.1,
  397. "conditions": []interface{}{
  398. map[string]interface{}{
  399. "path": "model",
  400. "mode": "prefix",
  401. "value": "gpt",
  402. "invert": true,
  403. },
  404. },
  405. },
  406. },
  407. }
  408. out, err := ApplyParamOverride(input, override, nil)
  409. if err != nil {
  410. t.Fatalf("ApplyParamOverride returned error: %v", err)
  411. }
  412. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
  413. }
  414. func TestApplyParamOverrideConditionPassMissingKey(t *testing.T) {
  415. input := []byte(`{"temperature":0.7}`)
  416. override := map[string]interface{}{
  417. "operations": []interface{}{
  418. map[string]interface{}{
  419. "path": "temperature",
  420. "mode": "set",
  421. "value": 0.1,
  422. "conditions": []interface{}{
  423. map[string]interface{}{
  424. "path": "model",
  425. "mode": "prefix",
  426. "value": "gpt",
  427. "pass_missing_key": true,
  428. },
  429. },
  430. },
  431. },
  432. }
  433. out, err := ApplyParamOverride(input, override, nil)
  434. if err != nil {
  435. t.Fatalf("ApplyParamOverride returned error: %v", err)
  436. }
  437. assertJSONEqual(t, `{"temperature":0.1}`, string(out))
  438. }
  439. func TestApplyParamOverrideConditionFromContext(t *testing.T) {
  440. input := []byte(`{"temperature":0.7}`)
  441. override := map[string]interface{}{
  442. "operations": []interface{}{
  443. map[string]interface{}{
  444. "path": "temperature",
  445. "mode": "set",
  446. "value": 0.1,
  447. "conditions": []interface{}{
  448. map[string]interface{}{
  449. "path": "model",
  450. "mode": "prefix",
  451. "value": "gpt",
  452. },
  453. },
  454. },
  455. },
  456. }
  457. ctx := map[string]interface{}{
  458. "model": "gpt-4",
  459. }
  460. out, err := ApplyParamOverride(input, override, ctx)
  461. if err != nil {
  462. t.Fatalf("ApplyParamOverride returned error: %v", err)
  463. }
  464. assertJSONEqual(t, `{"temperature":0.1}`, string(out))
  465. }
  466. func TestApplyParamOverrideNegativeIndexPath(t *testing.T) {
  467. input := []byte(`{"arr":[{"model":"a"},{"model":"b"}]}`)
  468. override := map[string]interface{}{
  469. "operations": []interface{}{
  470. map[string]interface{}{
  471. "path": "arr.-1.model",
  472. "mode": "set",
  473. "value": "c",
  474. },
  475. },
  476. }
  477. out, err := ApplyParamOverride(input, override, nil)
  478. if err != nil {
  479. t.Fatalf("ApplyParamOverride returned error: %v", err)
  480. }
  481. assertJSONEqual(t, `{"arr":[{"model":"a"},{"model":"c"}]}`, string(out))
  482. }
  483. func TestApplyParamOverrideRegexReplaceInvalidPattern(t *testing.T) {
  484. // regex_replace invalid pattern example:
  485. // {"operations":[{"path":"model","mode":"regex_replace","from":"(","to":"x"}]}
  486. input := []byte(`{"model":"gpt-4"}`)
  487. override := map[string]interface{}{
  488. "operations": []interface{}{
  489. map[string]interface{}{
  490. "path": "model",
  491. "mode": "regex_replace",
  492. "from": "(",
  493. "to": "x",
  494. },
  495. },
  496. }
  497. _, err := ApplyParamOverride(input, override, nil)
  498. if err == nil {
  499. t.Fatalf("expected error, got nil")
  500. }
  501. }
  502. func TestApplyParamOverrideCopy(t *testing.T) {
  503. // copy example:
  504. // {"operations":[{"mode":"copy","from":"model","to":"original_model"}]}
  505. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  506. override := map[string]interface{}{
  507. "operations": []interface{}{
  508. map[string]interface{}{
  509. "mode": "copy",
  510. "from": "model",
  511. "to": "original_model",
  512. },
  513. },
  514. }
  515. out, err := ApplyParamOverride(input, override, nil)
  516. if err != nil {
  517. t.Fatalf("ApplyParamOverride returned error: %v", err)
  518. }
  519. assertJSONEqual(t, `{"model":"gpt-4","original_model":"gpt-4","temperature":0.7}`, string(out))
  520. }
  521. func TestApplyParamOverrideCopyMissingSource(t *testing.T) {
  522. // copy missing source example:
  523. // {"operations":[{"mode":"copy","from":"model","to":"original_model"}]}
  524. input := []byte(`{"temperature":0.7}`)
  525. override := map[string]interface{}{
  526. "operations": []interface{}{
  527. map[string]interface{}{
  528. "mode": "copy",
  529. "from": "model",
  530. "to": "original_model",
  531. },
  532. },
  533. }
  534. _, err := ApplyParamOverride(input, override, nil)
  535. if err == nil {
  536. t.Fatalf("expected error, got nil")
  537. }
  538. }
  539. func TestApplyParamOverrideCopyRequiresFromTo(t *testing.T) {
  540. // copy requires from/to example:
  541. // {"operations":[{"mode":"copy"}]}
  542. input := []byte(`{"model":"gpt-4"}`)
  543. override := map[string]interface{}{
  544. "operations": []interface{}{
  545. map[string]interface{}{
  546. "mode": "copy",
  547. },
  548. },
  549. }
  550. _, err := ApplyParamOverride(input, override, nil)
  551. if err == nil {
  552. t.Fatalf("expected error, got nil")
  553. }
  554. }
  555. func TestApplyParamOverrideEnsurePrefix(t *testing.T) {
  556. // ensure_prefix example:
  557. // {"operations":[{"path":"model","mode":"ensure_prefix","value":"openai/"}]}
  558. input := []byte(`{"model":"gpt-4"}`)
  559. override := map[string]interface{}{
  560. "operations": []interface{}{
  561. map[string]interface{}{
  562. "path": "model",
  563. "mode": "ensure_prefix",
  564. "value": "openai/",
  565. },
  566. },
  567. }
  568. out, err := ApplyParamOverride(input, override, nil)
  569. if err != nil {
  570. t.Fatalf("ApplyParamOverride returned error: %v", err)
  571. }
  572. assertJSONEqual(t, `{"model":"openai/gpt-4"}`, string(out))
  573. }
  574. func TestApplyParamOverrideEnsurePrefixNoop(t *testing.T) {
  575. // ensure_prefix no-op example:
  576. // {"operations":[{"path":"model","mode":"ensure_prefix","value":"openai/"}]}
  577. input := []byte(`{"model":"openai/gpt-4"}`)
  578. override := map[string]interface{}{
  579. "operations": []interface{}{
  580. map[string]interface{}{
  581. "path": "model",
  582. "mode": "ensure_prefix",
  583. "value": "openai/",
  584. },
  585. },
  586. }
  587. out, err := ApplyParamOverride(input, override, nil)
  588. if err != nil {
  589. t.Fatalf("ApplyParamOverride returned error: %v", err)
  590. }
  591. assertJSONEqual(t, `{"model":"openai/gpt-4"}`, string(out))
  592. }
  593. func TestApplyParamOverrideEnsureSuffix(t *testing.T) {
  594. // ensure_suffix example:
  595. // {"operations":[{"path":"model","mode":"ensure_suffix","value":"-latest"}]}
  596. input := []byte(`{"model":"gpt-4"}`)
  597. override := map[string]interface{}{
  598. "operations": []interface{}{
  599. map[string]interface{}{
  600. "path": "model",
  601. "mode": "ensure_suffix",
  602. "value": "-latest",
  603. },
  604. },
  605. }
  606. out, err := ApplyParamOverride(input, override, nil)
  607. if err != nil {
  608. t.Fatalf("ApplyParamOverride returned error: %v", err)
  609. }
  610. assertJSONEqual(t, `{"model":"gpt-4-latest"}`, string(out))
  611. }
  612. func TestApplyParamOverrideEnsureSuffixNoop(t *testing.T) {
  613. // ensure_suffix no-op example:
  614. // {"operations":[{"path":"model","mode":"ensure_suffix","value":"-latest"}]}
  615. input := []byte(`{"model":"gpt-4-latest"}`)
  616. override := map[string]interface{}{
  617. "operations": []interface{}{
  618. map[string]interface{}{
  619. "path": "model",
  620. "mode": "ensure_suffix",
  621. "value": "-latest",
  622. },
  623. },
  624. }
  625. out, err := ApplyParamOverride(input, override, nil)
  626. if err != nil {
  627. t.Fatalf("ApplyParamOverride returned error: %v", err)
  628. }
  629. assertJSONEqual(t, `{"model":"gpt-4-latest"}`, string(out))
  630. }
  631. func TestApplyParamOverrideEnsureRequiresValue(t *testing.T) {
  632. // ensure_prefix requires value example:
  633. // {"operations":[{"path":"model","mode":"ensure_prefix"}]}
  634. input := []byte(`{"model":"gpt-4"}`)
  635. override := map[string]interface{}{
  636. "operations": []interface{}{
  637. map[string]interface{}{
  638. "path": "model",
  639. "mode": "ensure_prefix",
  640. },
  641. },
  642. }
  643. _, err := ApplyParamOverride(input, override, nil)
  644. if err == nil {
  645. t.Fatalf("expected error, got nil")
  646. }
  647. }
  648. func TestApplyParamOverrideTrimSpace(t *testing.T) {
  649. // trim_space example:
  650. // {"operations":[{"path":"model","mode":"trim_space"}]}
  651. input := []byte("{\"model\":\" gpt-4 \\n\"}")
  652. override := map[string]interface{}{
  653. "operations": []interface{}{
  654. map[string]interface{}{
  655. "path": "model",
  656. "mode": "trim_space",
  657. },
  658. },
  659. }
  660. out, err := ApplyParamOverride(input, override, nil)
  661. if err != nil {
  662. t.Fatalf("ApplyParamOverride returned error: %v", err)
  663. }
  664. assertJSONEqual(t, `{"model":"gpt-4"}`, string(out))
  665. }
  666. func TestApplyParamOverrideToLower(t *testing.T) {
  667. // to_lower example:
  668. // {"operations":[{"path":"model","mode":"to_lower"}]}
  669. input := []byte(`{"model":"GPT-4"}`)
  670. override := map[string]interface{}{
  671. "operations": []interface{}{
  672. map[string]interface{}{
  673. "path": "model",
  674. "mode": "to_lower",
  675. },
  676. },
  677. }
  678. out, err := ApplyParamOverride(input, override, nil)
  679. if err != nil {
  680. t.Fatalf("ApplyParamOverride returned error: %v", err)
  681. }
  682. assertJSONEqual(t, `{"model":"gpt-4"}`, string(out))
  683. }
  684. func TestApplyParamOverrideToUpper(t *testing.T) {
  685. // to_upper example:
  686. // {"operations":[{"path":"model","mode":"to_upper"}]}
  687. input := []byte(`{"model":"gpt-4"}`)
  688. override := map[string]interface{}{
  689. "operations": []interface{}{
  690. map[string]interface{}{
  691. "path": "model",
  692. "mode": "to_upper",
  693. },
  694. },
  695. }
  696. out, err := ApplyParamOverride(input, override, nil)
  697. if err != nil {
  698. t.Fatalf("ApplyParamOverride returned error: %v", err)
  699. }
  700. assertJSONEqual(t, `{"model":"GPT-4"}`, string(out))
  701. }
  702. func assertJSONEqual(t *testing.T, want, got string) {
  703. t.Helper()
  704. var wantObj interface{}
  705. var gotObj interface{}
  706. if err := json.Unmarshal([]byte(want), &wantObj); err != nil {
  707. t.Fatalf("failed to unmarshal want JSON: %v", err)
  708. }
  709. if err := json.Unmarshal([]byte(got), &gotObj); err != nil {
  710. t.Fatalf("failed to unmarshal got JSON: %v", err)
  711. }
  712. if !reflect.DeepEqual(wantObj, gotObj) {
  713. t.Fatalf("json not equal\nwant: %s\ngot: %s", want, got)
  714. }
  715. }