parser_test.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. package parser
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "strings"
  7. "testing"
  8. "github.com/stretchr/testify/assert"
  9. )
  10. func TestParser(t *testing.T) {
  11. input := `
  12. FROM model1
  13. ADAPTER adapter1
  14. LICENSE MIT
  15. PARAMETER param1 value1
  16. PARAMETER param2 value2
  17. TEMPLATE template1
  18. `
  19. reader := strings.NewReader(input)
  20. commands, err := Parse(reader)
  21. assert.Nil(t, err)
  22. expectedCommands := []Command{
  23. {Name: "model", Args: "model1"},
  24. {Name: "adapter", Args: "adapter1"},
  25. {Name: "license", Args: "MIT"},
  26. {Name: "param1", Args: "value1"},
  27. {Name: "param2", Args: "value2"},
  28. {Name: "template", Args: "template1"},
  29. }
  30. assert.Equal(t, expectedCommands, commands)
  31. }
  32. func TestParserFrom(t *testing.T) {
  33. var cases = []struct {
  34. input string
  35. expected []Command
  36. err error
  37. }{
  38. {
  39. "FROM foo",
  40. []Command{{Name: "model", Args: "foo"}},
  41. nil,
  42. },
  43. {
  44. "FROM /path/to/model",
  45. []Command{{Name: "model", Args: "/path/to/model"}},
  46. nil,
  47. },
  48. {
  49. "FROM /path/to/model/fp16.bin",
  50. []Command{{Name: "model", Args: "/path/to/model/fp16.bin"}},
  51. nil,
  52. },
  53. {
  54. "FROM llama3:latest",
  55. []Command{{Name: "model", Args: "llama3:latest"}},
  56. nil,
  57. },
  58. {
  59. "FROM llama3:7b-instruct-q4_K_M",
  60. []Command{{Name: "model", Args: "llama3:7b-instruct-q4_K_M"}},
  61. nil,
  62. },
  63. {
  64. "", nil, errMissingFrom,
  65. },
  66. {
  67. "PARAMETER param1 value1",
  68. nil,
  69. errMissingFrom,
  70. },
  71. {
  72. "PARAMETER param1 value1\nFROM foo",
  73. []Command{{Name: "param1", Args: "value1"}, {Name: "model", Args: "foo"}},
  74. nil,
  75. },
  76. }
  77. for _, c := range cases {
  78. t.Run("", func(t *testing.T) {
  79. commands, err := Parse(strings.NewReader(c.input))
  80. assert.ErrorIs(t, err, c.err)
  81. assert.Equal(t, c.expected, commands)
  82. })
  83. }
  84. }
  85. func TestParserParametersMissingValue(t *testing.T) {
  86. input := `
  87. FROM foo
  88. PARAMETER param1
  89. `
  90. reader := strings.NewReader(input)
  91. _, err := Parse(reader)
  92. assert.ErrorIs(t, err, io.ErrUnexpectedEOF)
  93. }
  94. func TestParserBadCommand(t *testing.T) {
  95. input := `
  96. FROM foo
  97. BADCOMMAND param1 value1
  98. `
  99. _, err := Parse(strings.NewReader(input))
  100. assert.ErrorIs(t, err, errInvalidCommand)
  101. }
  102. func TestParserMessages(t *testing.T) {
  103. var cases = []struct {
  104. input string
  105. expected []Command
  106. err error
  107. }{
  108. {
  109. `
  110. FROM foo
  111. MESSAGE system You are a Parser. Always Parse things.
  112. `,
  113. []Command{
  114. {Name: "model", Args: "foo"},
  115. {Name: "message", Args: "system: You are a Parser. Always Parse things."},
  116. },
  117. nil,
  118. },
  119. {
  120. `
  121. FROM foo
  122. MESSAGE system You are a Parser. Always Parse things.`,
  123. []Command{
  124. {Name: "model", Args: "foo"},
  125. {Name: "message", Args: "system: You are a Parser. Always Parse things."},
  126. },
  127. nil,
  128. },
  129. {
  130. `
  131. FROM foo
  132. MESSAGE system You are a Parser. Always Parse things.
  133. MESSAGE user Hey there!
  134. MESSAGE assistant Hello, I want to parse all the things!
  135. `,
  136. []Command{
  137. {Name: "model", Args: "foo"},
  138. {Name: "message", Args: "system: You are a Parser. Always Parse things."},
  139. {Name: "message", Args: "user: Hey there!"},
  140. {Name: "message", Args: "assistant: Hello, I want to parse all the things!"},
  141. },
  142. nil,
  143. },
  144. {
  145. `
  146. FROM foo
  147. MESSAGE system """
  148. You are a multiline Parser. Always Parse things.
  149. """
  150. `,
  151. []Command{
  152. {Name: "model", Args: "foo"},
  153. {Name: "message", Args: "system: \nYou are a multiline Parser. Always Parse things.\n"},
  154. },
  155. nil,
  156. },
  157. {
  158. `
  159. FROM foo
  160. MESSAGE badguy I'm a bad guy!
  161. `,
  162. nil,
  163. errInvalidMessageRole,
  164. },
  165. {
  166. `
  167. FROM foo
  168. MESSAGE system
  169. `,
  170. nil,
  171. io.ErrUnexpectedEOF,
  172. },
  173. {
  174. `
  175. FROM foo
  176. MESSAGE system`,
  177. nil,
  178. io.ErrUnexpectedEOF,
  179. },
  180. }
  181. for _, c := range cases {
  182. t.Run("", func(t *testing.T) {
  183. commands, err := Parse(strings.NewReader(c.input))
  184. assert.ErrorIs(t, err, c.err)
  185. assert.Equal(t, c.expected, commands)
  186. })
  187. }
  188. }
  189. func TestParserQuoted(t *testing.T) {
  190. var cases = []struct {
  191. multiline string
  192. expected []Command
  193. err error
  194. }{
  195. {
  196. `
  197. FROM foo
  198. SYSTEM """
  199. This is a
  200. multiline system.
  201. """
  202. `,
  203. []Command{
  204. {Name: "model", Args: "foo"},
  205. {Name: "system", Args: "\nThis is a\nmultiline system.\n"},
  206. },
  207. nil,
  208. },
  209. {
  210. `
  211. FROM foo
  212. SYSTEM """
  213. This is a
  214. multiline system."""
  215. `,
  216. []Command{
  217. {Name: "model", Args: "foo"},
  218. {Name: "system", Args: "\nThis is a\nmultiline system."},
  219. },
  220. nil,
  221. },
  222. {
  223. `
  224. FROM foo
  225. SYSTEM """This is a
  226. multiline system."""
  227. `,
  228. []Command{
  229. {Name: "model", Args: "foo"},
  230. {Name: "system", Args: "This is a\nmultiline system."},
  231. },
  232. nil,
  233. },
  234. {
  235. `
  236. FROM foo
  237. SYSTEM """This is a multiline system."""
  238. `,
  239. []Command{
  240. {Name: "model", Args: "foo"},
  241. {Name: "system", Args: "This is a multiline system."},
  242. },
  243. nil,
  244. },
  245. {
  246. `
  247. FROM foo
  248. SYSTEM """This is a multiline system.""
  249. `,
  250. nil,
  251. io.ErrUnexpectedEOF,
  252. },
  253. {
  254. `
  255. FROM foo
  256. SYSTEM "
  257. `,
  258. nil,
  259. io.ErrUnexpectedEOF,
  260. },
  261. {
  262. `
  263. FROM foo
  264. SYSTEM """
  265. This is a multiline system with "quotes".
  266. """
  267. `,
  268. []Command{
  269. {Name: "model", Args: "foo"},
  270. {Name: "system", Args: "\nThis is a multiline system with \"quotes\".\n"},
  271. },
  272. nil,
  273. },
  274. {
  275. `
  276. FROM foo
  277. SYSTEM """"""
  278. `,
  279. []Command{
  280. {Name: "model", Args: "foo"},
  281. {Name: "system", Args: ""},
  282. },
  283. nil,
  284. },
  285. {
  286. `
  287. FROM foo
  288. SYSTEM ""
  289. `,
  290. []Command{
  291. {Name: "model", Args: "foo"},
  292. {Name: "system", Args: ""},
  293. },
  294. nil,
  295. },
  296. {
  297. `
  298. FROM foo
  299. SYSTEM "'"
  300. `,
  301. []Command{
  302. {Name: "model", Args: "foo"},
  303. {Name: "system", Args: "'"},
  304. },
  305. nil,
  306. },
  307. {
  308. `
  309. FROM foo
  310. SYSTEM """''"'""'""'"'''''""'""'"""
  311. `,
  312. []Command{
  313. {Name: "model", Args: "foo"},
  314. {Name: "system", Args: `''"'""'""'"'''''""'""'`},
  315. },
  316. nil,
  317. },
  318. {
  319. `
  320. FROM foo
  321. TEMPLATE """
  322. {{ .Prompt }}
  323. """`,
  324. []Command{
  325. {Name: "model", Args: "foo"},
  326. {Name: "template", Args: "\n{{ .Prompt }}\n"},
  327. },
  328. nil,
  329. },
  330. }
  331. for _, c := range cases {
  332. t.Run("", func(t *testing.T) {
  333. commands, err := Parse(strings.NewReader(c.multiline))
  334. assert.ErrorIs(t, err, c.err)
  335. assert.Equal(t, c.expected, commands)
  336. })
  337. }
  338. }
  339. func TestParserParameters(t *testing.T) {
  340. var cases = map[string]struct {
  341. name, value string
  342. }{
  343. "numa true": {"numa", "true"},
  344. "num_ctx 1": {"num_ctx", "1"},
  345. "num_batch 1": {"num_batch", "1"},
  346. "num_gqa 1": {"num_gqa", "1"},
  347. "num_gpu 1": {"num_gpu", "1"},
  348. "main_gpu 1": {"main_gpu", "1"},
  349. "low_vram true": {"low_vram", "true"},
  350. "f16_kv true": {"f16_kv", "true"},
  351. "logits_all true": {"logits_all", "true"},
  352. "vocab_only true": {"vocab_only", "true"},
  353. "use_mmap true": {"use_mmap", "true"},
  354. "use_mlock true": {"use_mlock", "true"},
  355. "num_thread 1": {"num_thread", "1"},
  356. "num_keep 1": {"num_keep", "1"},
  357. "seed 1": {"seed", "1"},
  358. "num_predict 1": {"num_predict", "1"},
  359. "top_k 1": {"top_k", "1"},
  360. "top_p 1.0": {"top_p", "1.0"},
  361. "tfs_z 1.0": {"tfs_z", "1.0"},
  362. "typical_p 1.0": {"typical_p", "1.0"},
  363. "repeat_last_n 1": {"repeat_last_n", "1"},
  364. "temperature 1.0": {"temperature", "1.0"},
  365. "repeat_penalty 1.0": {"repeat_penalty", "1.0"},
  366. "presence_penalty 1.0": {"presence_penalty", "1.0"},
  367. "frequency_penalty 1.0": {"frequency_penalty", "1.0"},
  368. "mirostat 1": {"mirostat", "1"},
  369. "mirostat_tau 1.0": {"mirostat_tau", "1.0"},
  370. "mirostat_eta 1.0": {"mirostat_eta", "1.0"},
  371. "penalize_newline true": {"penalize_newline", "true"},
  372. "stop ### User:": {"stop", "### User:"},
  373. "stop ### User: ": {"stop", "### User: "},
  374. "stop \"### User:\"": {"stop", "### User:"},
  375. "stop \"### User: \"": {"stop", "### User: "},
  376. "stop \"\"\"### User:\"\"\"": {"stop", "### User:"},
  377. "stop \"\"\"### User:\n\"\"\"": {"stop", "### User:\n"},
  378. "stop <|endoftext|>": {"stop", "<|endoftext|>"},
  379. "stop <|eot_id|>": {"stop", "<|eot_id|>"},
  380. "stop </s>": {"stop", "</s>"},
  381. }
  382. for k, v := range cases {
  383. t.Run(k, func(t *testing.T) {
  384. var b bytes.Buffer
  385. fmt.Fprintln(&b, "FROM foo")
  386. fmt.Fprintln(&b, "PARAMETER", k)
  387. commands, err := Parse(&b)
  388. assert.Nil(t, err)
  389. assert.Equal(t, []Command{
  390. {Name: "model", Args: "foo"},
  391. {Name: v.name, Args: v.value},
  392. }, commands)
  393. })
  394. }
  395. }
  396. func TestParserComments(t *testing.T) {
  397. var cases = []struct {
  398. input string
  399. expected []Command
  400. }{
  401. {
  402. `
  403. # comment
  404. FROM foo
  405. `,
  406. []Command{
  407. {Name: "model", Args: "foo"},
  408. },
  409. },
  410. }
  411. for _, c := range cases {
  412. t.Run("", func(t *testing.T) {
  413. commands, err := Parse(strings.NewReader(c.input))
  414. assert.Nil(t, err)
  415. assert.Equal(t, c.expected, commands)
  416. })
  417. }
  418. }
  419. func TestParseFormatParse(t *testing.T) {
  420. var cases = []string{
  421. `
  422. FROM foo
  423. ADAPTER adapter1
  424. LICENSE MIT
  425. PARAMETER param1 value1
  426. PARAMETER param2 value2
  427. TEMPLATE template1
  428. MESSAGE system You are a Parser. Always Parse things.
  429. MESSAGE user Hey there!
  430. MESSAGE assistant Hello, I want to parse all the things!
  431. `,
  432. `
  433. FROM foo
  434. ADAPTER adapter1
  435. LICENSE MIT
  436. PARAMETER param1 value1
  437. PARAMETER param2 value2
  438. TEMPLATE template1
  439. MESSAGE system """
  440. You are a store greeter. Always responsed with "Hello!".
  441. """
  442. MESSAGE user Hey there!
  443. MESSAGE assistant Hello, I want to parse all the things!
  444. `,
  445. `
  446. FROM foo
  447. ADAPTER adapter1
  448. LICENSE """
  449. Very long and boring legal text.
  450. Blah blah blah.
  451. "Oh look, a quote!"
  452. """
  453. PARAMETER param1 value1
  454. PARAMETER param2 value2
  455. TEMPLATE template1
  456. MESSAGE system """
  457. You are a store greeter. Always responsed with "Hello!".
  458. """
  459. MESSAGE user Hey there!
  460. MESSAGE assistant Hello, I want to parse all the things!
  461. `,
  462. }
  463. for _, c := range cases {
  464. t.Run("", func(t *testing.T) {
  465. commands, err := Parse(strings.NewReader(c))
  466. assert.NoError(t, err)
  467. commands2, err := Parse(strings.NewReader(Format(commands)))
  468. assert.NoError(t, err)
  469. assert.Equal(t, commands, commands2)
  470. })
  471. }
  472. }