You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1536 lines
42 KiB

  1. /*
  2. Based of off docopt.py: https://github.com/docopt/docopt
  3. Licensed under terms of MIT license (see LICENSE-MIT)
  4. Copyright (c) 2013 Keith Batten, kbatten@gmail.com
  5. */
  6. package docopt
  7. import (
  8. "bytes"
  9. "encoding/json"
  10. "fmt"
  11. "io"
  12. "io/ioutil"
  13. "os"
  14. "reflect"
  15. "regexp"
  16. "strings"
  17. "testing"
  18. )
  19. func TestPatternFlat(t *testing.T) {
  20. q := patternList{
  21. newArgument("N", nil),
  22. newOption("-a", "", 0, false),
  23. newArgument("M", nil)}
  24. p, err := newRequired(
  25. newOneOrMore(newArgument("N", nil)),
  26. newOption("-a", "", 0, false),
  27. newArgument("M", nil)).flat(patternDefault)
  28. if reflect.DeepEqual(p, q) != true {
  29. t.Error(err)
  30. }
  31. q = patternList{newOptionsShortcut()}
  32. p, err = newRequired(
  33. newOptional(newOptionsShortcut()),
  34. newOptional(newOption("-a", "", 0, false))).flat(patternOptionSSHORTCUT)
  35. if reflect.DeepEqual(p, q) != true {
  36. t.Error(err)
  37. }
  38. return
  39. }
  40. func TestOption(t *testing.T) {
  41. if !parseOption("-h").eq(newOption("-h", "", 0, false)) {
  42. t.Fail()
  43. }
  44. if !parseOption("--help").eq(newOption("", "--help", 0, false)) {
  45. t.Fail()
  46. }
  47. if !parseOption("-h --help").eq(newOption("-h", "--help", 0, false)) {
  48. t.Fail()
  49. }
  50. if !parseOption("-h, --help").eq(newOption("-h", "--help", 0, false)) {
  51. t.Fail()
  52. }
  53. if !parseOption("-h TOPIC").eq(newOption("-h", "", 1, false)) {
  54. t.Fail()
  55. }
  56. if !parseOption("--help TOPIC").eq(newOption("", "--help", 1, false)) {
  57. t.Fail()
  58. }
  59. if !parseOption("-h TOPIC --help TOPIC").eq(newOption("-h", "--help", 1, false)) {
  60. t.Fail()
  61. }
  62. if !parseOption("-h TOPIC, --help TOPIC").eq(newOption("-h", "--help", 1, false)) {
  63. t.Fail()
  64. }
  65. if !parseOption("-h TOPIC, --help=TOPIC").eq(newOption("-h", "--help", 1, false)) {
  66. t.Fail()
  67. }
  68. if !parseOption("-h Description...").eq(newOption("-h", "", 0, false)) {
  69. t.Fail()
  70. }
  71. if !parseOption("-h --help Description...").eq(newOption("-h", "--help", 0, false)) {
  72. t.Fail()
  73. }
  74. if !parseOption("-h TOPIC Description...").eq(newOption("-h", "", 1, false)) {
  75. t.Fail()
  76. }
  77. if !parseOption(" -h").eq(newOption("-h", "", 0, false)) {
  78. t.Fail()
  79. }
  80. if !parseOption("-h TOPIC Description... [default: 2]").eq(newOption("-h", "", 1, "2")) {
  81. t.Fail()
  82. }
  83. if !parseOption("-h TOPIC Descripton... [default: topic-1]").eq(newOption("-h", "", 1, "topic-1")) {
  84. t.Fail()
  85. }
  86. if !parseOption("--help=TOPIC ... [default: 3.14]").eq(newOption("", "--help", 1, "3.14")) {
  87. t.Fail()
  88. }
  89. if !parseOption("-h, --help=DIR ... [default: ./]").eq(newOption("-h", "--help", 1, "./")) {
  90. t.Fail()
  91. }
  92. if !parseOption("-h TOPIC Descripton... [dEfAuLt: 2]").eq(newOption("-h", "", 1, "2")) {
  93. t.Fail()
  94. }
  95. return
  96. }
  97. func TestOptionName(t *testing.T) {
  98. if newOption("-h", "", 0, false).name != "-h" {
  99. t.Fail()
  100. }
  101. if newOption("-h", "--help", 0, false).name != "--help" {
  102. t.Fail()
  103. }
  104. if newOption("", "--help", 0, false).name != "--help" {
  105. t.Fail()
  106. }
  107. return
  108. }
  109. func TestCommands(t *testing.T) {
  110. if v, err := Parse("Usage: prog add", []string{"add"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": true}) != true {
  111. t.Error(err)
  112. }
  113. if v, err := Parse("Usage: prog [add]", []string{}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": false}) != true {
  114. t.Error(err)
  115. }
  116. if v, err := Parse("Usage: prog [add]", []string{"add"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": true}) != true {
  117. t.Error(err)
  118. }
  119. if v, err := Parse("Usage: prog (add|rm)", []string{"add"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": true, "rm": false}) != true {
  120. t.Error(err)
  121. }
  122. if v, err := Parse("Usage: prog (add|rm)", []string{"rm"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": false, "rm": true}) != true {
  123. t.Error(err)
  124. }
  125. if v, err := Parse("Usage: prog a b", []string{"a", "b"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"a": true, "b": true}) != true {
  126. t.Error(err)
  127. }
  128. _, err := Parse("Usage: prog a b", []string{"b", "a"}, true, "", false, false)
  129. if _, ok := err.(*UserError); !ok {
  130. t.Error(err)
  131. }
  132. return
  133. }
  134. func TestFormalUsage(t *testing.T) {
  135. doc := `
  136. Usage: prog [-hv] ARG
  137. prog N M
  138. prog is a program`
  139. usage := parseSection("usage:", doc)[0]
  140. if usage != "Usage: prog [-hv] ARG\n prog N M" {
  141. t.FailNow()
  142. }
  143. formal, err := formalUsage(usage)
  144. if err != nil {
  145. t.Fatal(err)
  146. }
  147. if formal != "( [-hv] ARG ) | ( N M )" {
  148. t.Fail()
  149. }
  150. return
  151. }
  152. func TestParseArgv(t *testing.T) {
  153. o := patternList{
  154. newOption("-h", "", 0, false),
  155. newOption("-v", "--verbose", 0, false),
  156. newOption("-f", "--file", 1, false),
  157. }
  158. p, err := parseArgv(tokenListFromString(""), &o, false)
  159. q := patternList{}
  160. if reflect.DeepEqual(p, q) != true {
  161. t.Error(err)
  162. }
  163. p, err = parseArgv(tokenListFromString("-h"), &o, false)
  164. q = patternList{newOption("-h", "", 0, true)}
  165. if reflect.DeepEqual(p, q) != true {
  166. t.Error(err)
  167. }
  168. p, err = parseArgv(tokenListFromString("-h --verbose"), &o, false)
  169. q = patternList{
  170. newOption("-h", "", 0, true),
  171. newOption("-v", "--verbose", 0, true),
  172. }
  173. if reflect.DeepEqual(p, q) != true {
  174. t.Error(err)
  175. }
  176. p, err = parseArgv(tokenListFromString("-h --file f.txt"), &o, false)
  177. q = patternList{
  178. newOption("-h", "", 0, true),
  179. newOption("-f", "--file", 1, "f.txt"),
  180. }
  181. if reflect.DeepEqual(p, q) != true {
  182. t.Error(err)
  183. }
  184. p, err = parseArgv(tokenListFromString("-h --file f.txt arg"), &o, false)
  185. q = patternList{
  186. newOption("-h", "", 0, true),
  187. newOption("-f", "--file", 1, "f.txt"),
  188. newArgument("", "arg"),
  189. }
  190. if reflect.DeepEqual(p, q) != true {
  191. t.Error(err)
  192. }
  193. p, err = parseArgv(tokenListFromString("-h --file f.txt arg arg2"), &o, false)
  194. q = patternList{
  195. newOption("-h", "", 0, true),
  196. newOption("-f", "--file", 1, "f.txt"),
  197. newArgument("", "arg"),
  198. newArgument("", "arg2"),
  199. }
  200. if reflect.DeepEqual(p, q) != true {
  201. t.Error(err)
  202. }
  203. p, err = parseArgv(tokenListFromString("-h arg -- -v"), &o, false)
  204. q = patternList{
  205. newOption("-h", "", 0, true),
  206. newArgument("", "arg"),
  207. newArgument("", "--"),
  208. newArgument("", "-v"),
  209. }
  210. if reflect.DeepEqual(p, q) != true {
  211. t.Error(err)
  212. }
  213. }
  214. func TestParsePattern(t *testing.T) {
  215. o := patternList{
  216. newOption("-h", "", 0, false),
  217. newOption("-v", "--verbose", 0, false),
  218. newOption("-f", "--file", 1, false),
  219. }
  220. p, err := parsePattern("[ -h ]", &o)
  221. q := newRequired(newOptional(newOption("-h", "", 0, false)))
  222. if p.eq(q) != true {
  223. t.Error(err)
  224. }
  225. p, err = parsePattern("[ ARG ... ]", &o)
  226. q = newRequired(newOptional(
  227. newOneOrMore(
  228. newArgument("ARG", nil))))
  229. if p.eq(q) != true {
  230. t.Error(err)
  231. }
  232. p, err = parsePattern("[ -h | -v ]", &o)
  233. q = newRequired(
  234. newOptional(
  235. newEither(
  236. newOption("-h", "", 0, false),
  237. newOption("-v", "--verbose", 0, false))))
  238. if p.eq(q) != true {
  239. t.Error(err)
  240. }
  241. p, err = parsePattern("( -h | -v [ --file <f> ] )", &o)
  242. q = newRequired(
  243. newRequired(
  244. newEither(
  245. newOption("-h", "", 0, false),
  246. newRequired(
  247. newOption("-v", "--verbose", 0, false),
  248. newOptional(
  249. newOption("-f", "--file", 1, nil))))))
  250. if p.eq(q) != true {
  251. t.Error(err)
  252. }
  253. p, err = parsePattern("(-h|-v[--file=<f>]N...)", &o)
  254. q = newRequired(
  255. newRequired(
  256. newEither(
  257. newOption("-h", "", 0, false),
  258. newRequired(
  259. newOption("-v", "--verbose", 0, false),
  260. newOptional(
  261. newOption("-f", "--file", 1, nil)),
  262. newOneOrMore(
  263. newArgument("N", nil))))))
  264. if p.eq(q) != true {
  265. t.Error(err)
  266. }
  267. p, err = parsePattern("(N [M | (K | L)] | O P)", &o)
  268. q = newRequired(
  269. newRequired(
  270. newEither(
  271. newRequired(
  272. newArgument("N", nil),
  273. newOptional(
  274. newEither(
  275. newArgument("M", nil),
  276. newRequired(
  277. newEither(
  278. newArgument("K", nil),
  279. newArgument("L", nil)))))),
  280. newRequired(
  281. newArgument("O", nil),
  282. newArgument("P", nil)))))
  283. if p.eq(q) != true {
  284. t.Error(err)
  285. }
  286. p, err = parsePattern("[ -h ] [N]", &o)
  287. q = newRequired(
  288. newOptional(
  289. newOption("-h", "", 0, false)),
  290. newOptional(
  291. newArgument("N", nil)))
  292. if p.eq(q) != true {
  293. t.Error(err)
  294. }
  295. p, err = parsePattern("[options]", &o)
  296. q = newRequired(
  297. newOptional(
  298. newOptionsShortcut()))
  299. if p.eq(q) != true {
  300. t.Error(err)
  301. }
  302. p, err = parsePattern("[options] A", &o)
  303. q = newRequired(
  304. newOptional(
  305. newOptionsShortcut()),
  306. newArgument("A", nil))
  307. if p.eq(q) != true {
  308. t.Error(err)
  309. }
  310. p, err = parsePattern("-v [options]", &o)
  311. q = newRequired(
  312. newOption("-v", "--verbose", 0, false),
  313. newOptional(
  314. newOptionsShortcut()))
  315. if p.eq(q) != true {
  316. t.Error(err)
  317. }
  318. p, err = parsePattern("ADD", &o)
  319. q = newRequired(newArgument("ADD", nil))
  320. if p.eq(q) != true {
  321. t.Error(err)
  322. }
  323. p, err = parsePattern("<add>", &o)
  324. q = newRequired(newArgument("<add>", nil))
  325. if p.eq(q) != true {
  326. t.Error(err)
  327. }
  328. p, err = parsePattern("add", &o)
  329. q = newRequired(newCommand("add", false))
  330. if p.eq(q) != true {
  331. t.Error(err)
  332. }
  333. }
  334. func TestOptionMatch(t *testing.T) {
  335. v, w, x := newOption("-a", "", 0, false).match(
  336. &patternList{newOption("-a", "", 0, true)}, nil)
  337. y := patternList{newOption("-a", "", 0, true)}
  338. if v != true ||
  339. reflect.DeepEqual(*w, patternList{}) != true ||
  340. reflect.DeepEqual(*x, y) != true {
  341. t.Fail()
  342. }
  343. v, w, x = newOption("-a", "", 0, false).match(
  344. &patternList{newOption("-x", "", 0, false)}, nil)
  345. y = patternList{newOption("-x", "", 0, false)}
  346. if v != false ||
  347. reflect.DeepEqual(*w, y) != true ||
  348. reflect.DeepEqual(*x, patternList{}) != true {
  349. t.Fail()
  350. }
  351. v, w, x = newOption("-a", "", 0, false).match(
  352. &patternList{newOption("-x", "", 0, false)}, nil)
  353. y = patternList{newOption("-x", "", 0, false)}
  354. if v != false ||
  355. reflect.DeepEqual(*w, y) != true ||
  356. reflect.DeepEqual(*x, patternList{}) != true {
  357. t.Fail()
  358. }
  359. v, w, x = newOption("-a", "", 0, false).match(
  360. &patternList{newArgument("N", nil)}, nil)
  361. y = patternList{newArgument("N", nil)}
  362. if v != false ||
  363. reflect.DeepEqual(*w, y) != true ||
  364. reflect.DeepEqual(*x, patternList{}) != true {
  365. t.Fail()
  366. }
  367. v, w, x = newOption("-a", "", 0, false).match(
  368. &patternList{
  369. newOption("-x", "", 0, false),
  370. newOption("-a", "", 0, false),
  371. newArgument("N", nil)}, nil)
  372. y = patternList{
  373. newOption("-x", "", 0, false),
  374. newArgument("N", nil)}
  375. z := patternList{newOption("-a", "", 0, false)}
  376. if v != true ||
  377. reflect.DeepEqual(*w, y) != true ||
  378. reflect.DeepEqual(*x, z) != true {
  379. t.Fail()
  380. }
  381. v, w, x = newOption("-a", "", 0, false).match(
  382. &patternList{
  383. newOption("-a", "", 0, true),
  384. newOption("-a", "", 0, false)}, nil)
  385. y = patternList{newOption("-a", "", 0, false)}
  386. z = patternList{newOption("-a", "", 0, true)}
  387. if v != true ||
  388. reflect.DeepEqual(*w, y) != true ||
  389. reflect.DeepEqual(*x, z) != true {
  390. t.Fail()
  391. }
  392. }
  393. func TestArgumentMatch(t *testing.T) {
  394. v, w, x := newArgument("N", nil).match(
  395. &patternList{newArgument("N", 9)}, nil)
  396. y := patternList{newArgument("N", 9)}
  397. if v != true ||
  398. reflect.DeepEqual(*w, patternList{}) != true ||
  399. reflect.DeepEqual(*x, y) != true {
  400. t.Fail()
  401. }
  402. v, w, x = newArgument("N", nil).match(
  403. &patternList{newOption("-x", "", 0, false)}, nil)
  404. y = patternList{newOption("-x", "", 0, false)}
  405. if v != false ||
  406. reflect.DeepEqual(*w, y) != true ||
  407. reflect.DeepEqual(*x, patternList{}) != true {
  408. t.Fail()
  409. }
  410. v, w, x = newArgument("N", nil).match(
  411. &patternList{newOption("-x", "", 0, false),
  412. newOption("-a", "", 0, false),
  413. newArgument("", 5)}, nil)
  414. y = patternList{newOption("-x", "", 0, false),
  415. newOption("-a", "", 0, false)}
  416. z := patternList{newArgument("N", 5)}
  417. if v != true ||
  418. reflect.DeepEqual(*w, y) != true ||
  419. reflect.DeepEqual(*x, z) != true {
  420. t.Fail()
  421. }
  422. v, w, x = newArgument("N", nil).match(
  423. &patternList{newArgument("", 9),
  424. newArgument("", 0)}, nil)
  425. y = patternList{newArgument("", 0)}
  426. z = patternList{newArgument("N", 9)}
  427. if v != true ||
  428. reflect.DeepEqual(*w, y) != true ||
  429. reflect.DeepEqual(*x, z) != true {
  430. t.Fail()
  431. }
  432. }
  433. func TestCommandMatch(t *testing.T) {
  434. v, w, x := newCommand("c", false).match(
  435. &patternList{newArgument("", "c")}, nil)
  436. y := patternList{newCommand("c", true)}
  437. if v != true ||
  438. reflect.DeepEqual(*w, patternList{}) != true ||
  439. reflect.DeepEqual(*x, y) != true {
  440. t.Fail()
  441. }
  442. v, w, x = newCommand("c", false).match(
  443. &patternList{newOption("-x", "", 0, false)}, nil)
  444. y = patternList{newOption("-x", "", 0, false)}
  445. if v != false ||
  446. reflect.DeepEqual(*w, y) != true ||
  447. reflect.DeepEqual(*x, patternList{}) != true {
  448. t.Fail()
  449. }
  450. v, w, x = newCommand("c", false).match(
  451. &patternList{
  452. newOption("-x", "", 0, false),
  453. newOption("-a", "", 0, false),
  454. newArgument("", "c")}, nil)
  455. y = patternList{newOption("-x", "", 0, false),
  456. newOption("-a", "", 0, false)}
  457. z := patternList{newCommand("c", true)}
  458. if v != true ||
  459. reflect.DeepEqual(*w, y) != true ||
  460. reflect.DeepEqual(*x, z) != true {
  461. t.Fail()
  462. }
  463. v, w, x = newEither(
  464. newCommand("add", false),
  465. newCommand("rm", false)).match(
  466. &patternList{newArgument("", "rm")}, nil)
  467. y = patternList{newCommand("rm", true)}
  468. if v != true ||
  469. reflect.DeepEqual(*w, patternList{}) != true ||
  470. reflect.DeepEqual(*x, y) != true {
  471. t.Fail()
  472. }
  473. }
  474. func TestOptionalMatch(t *testing.T) {
  475. v, w, x := newOptional(newOption("-a", "", 0, false)).match(
  476. &patternList{newOption("-a", "", 0, false)}, nil)
  477. y := patternList{newOption("-a", "", 0, false)}
  478. if v != true ||
  479. reflect.DeepEqual(*w, patternList{}) != true ||
  480. reflect.DeepEqual(*x, y) != true {
  481. t.Fail()
  482. }
  483. v, w, x = newOptional(newOption("-a", "", 0, false)).match(
  484. &patternList{}, nil)
  485. if v != true ||
  486. reflect.DeepEqual(*w, patternList{}) != true ||
  487. reflect.DeepEqual(*x, patternList{}) != true {
  488. t.Fail()
  489. }
  490. v, w, x = newOptional(newOption("-a", "", 0, false)).match(
  491. &patternList{newOption("-x", "", 0, false)}, nil)
  492. y = patternList{newOption("-x", "", 0, false)}
  493. if v != true ||
  494. reflect.DeepEqual(*w, y) != true ||
  495. reflect.DeepEqual(*x, patternList{}) != true {
  496. t.Fail()
  497. }
  498. v, w, x = newOptional(newOption("-a", "", 0, false),
  499. newOption("-b", "", 0, false)).match(
  500. &patternList{newOption("-a", "", 0, false)}, nil)
  501. y = patternList{newOption("-a", "", 0, false)}
  502. if v != true ||
  503. reflect.DeepEqual(*w, patternList{}) != true ||
  504. reflect.DeepEqual(*x, y) != true {
  505. t.Fail()
  506. }
  507. v, w, x = newOptional(newOption("-a", "", 0, false),
  508. newOption("-b", "", 0, false)).match(
  509. &patternList{newOption("-b", "", 0, false)}, nil)
  510. y = patternList{newOption("-b", "", 0, false)}
  511. if v != true ||
  512. reflect.DeepEqual(*w, patternList{}) != true ||
  513. reflect.DeepEqual(*x, y) != true {
  514. t.Fail()
  515. }
  516. v, w, x = newOptional(newOption("-a", "", 0, false),
  517. newOption("-b", "", 0, false)).match(
  518. &patternList{newOption("-x", "", 0, false)}, nil)
  519. y = patternList{newOption("-x", "", 0, false)}
  520. if v != true ||
  521. reflect.DeepEqual(*w, y) != true ||
  522. reflect.DeepEqual(*x, patternList{}) != true {
  523. t.Fail()
  524. }
  525. v, w, x = newOptional(newArgument("N", nil)).match(
  526. &patternList{newArgument("", 9)}, nil)
  527. y = patternList{newArgument("N", 9)}
  528. if v != true ||
  529. reflect.DeepEqual(*w, patternList{}) != true ||
  530. reflect.DeepEqual(*x, y) != true {
  531. t.Fail()
  532. }
  533. v, w, x = newOptional(newOption("-a", "", 0, false),
  534. newOption("-b", "", 0, false)).match(
  535. &patternList{newOption("-b", "", 0, false),
  536. newOption("-x", "", 0, false),
  537. newOption("-a", "", 0, false)}, nil)
  538. y = patternList{newOption("-x", "", 0, false)}
  539. z := patternList{newOption("-a", "", 0, false),
  540. newOption("-b", "", 0, false)}
  541. if v != true ||
  542. reflect.DeepEqual(*w, y) != true ||
  543. reflect.DeepEqual(*x, z) != true {
  544. t.Fail()
  545. }
  546. }
  547. func TestRequiredMatch(t *testing.T) {
  548. v, w, x := newRequired(newOption("-a", "", 0, false)).match(
  549. &patternList{newOption("-a", "", 0, false)}, nil)
  550. y := patternList{newOption("-a", "", 0, false)}
  551. if v != true ||
  552. reflect.DeepEqual(*w, patternList{}) != true ||
  553. reflect.DeepEqual(*x, y) != true {
  554. t.Fail()
  555. }
  556. v, w, x = newRequired(newOption("-a", "", 0, false)).match(&patternList{}, nil)
  557. if v != false ||
  558. reflect.DeepEqual(*w, patternList{}) != true ||
  559. reflect.DeepEqual(*x, patternList{}) != true {
  560. t.Fail()
  561. }
  562. v, w, x = newRequired(newOption("-a", "", 0, false)).match(
  563. &patternList{newOption("-x", "", 0, false)}, nil)
  564. y = patternList{newOption("-x", "", 0, false)}
  565. if v != false ||
  566. reflect.DeepEqual(*w, y) != true ||
  567. reflect.DeepEqual(*x, patternList{}) != true {
  568. t.Fail()
  569. }
  570. v, w, x = newRequired(newOption("-a", "", 0, false),
  571. newOption("-b", "", 0, false)).match(
  572. &patternList{newOption("-a", "", 0, false)}, nil)
  573. y = patternList{newOption("-a", "", 0, false)}
  574. if v != false ||
  575. reflect.DeepEqual(*w, y) != true ||
  576. reflect.DeepEqual(*x, patternList{}) != true {
  577. t.Fail()
  578. }
  579. }
  580. func TestEitherMatch(t *testing.T) {
  581. v, w, x := newEither(
  582. newOption("-a", "", 0, false),
  583. newOption("-b", "", 0, false)).match(
  584. &patternList{newOption("-a", "", 0, false)}, nil)
  585. y := patternList{newOption("-a", "", 0, false)}
  586. if v != true ||
  587. reflect.DeepEqual(*w, patternList{}) != true ||
  588. reflect.DeepEqual(*x, y) != true {
  589. t.Fail()
  590. }
  591. v, w, x = newEither(
  592. newOption("-a", "", 0, false),
  593. newOption("-b", "", 0, false)).match(&patternList{
  594. newOption("-a", "", 0, false),
  595. newOption("-b", "", 0, false)}, nil)
  596. y = patternList{newOption("-b", "", 0, false)}
  597. z := patternList{newOption("-a", "", 0, false)}
  598. if v != true ||
  599. reflect.DeepEqual(*w, y) != true ||
  600. reflect.DeepEqual(*x, z) != true {
  601. t.Fail()
  602. }
  603. v, w, x = newEither(
  604. newOption("-a", "", 0, false),
  605. newOption("-b", "", 0, false)).match(&patternList{
  606. newOption("-x", "", 0, false)}, nil)
  607. y = patternList{newOption("-x", "", 0, false)}
  608. z = patternList{}
  609. if v != false ||
  610. reflect.DeepEqual(*w, y) != true ||
  611. reflect.DeepEqual(*x, z) != true {
  612. t.Fail()
  613. }
  614. v, w, x = newEither(
  615. newOption("-a", "", 0, false),
  616. newOption("-b", "", 0, false),
  617. newOption("-c", "", 0, false)).match(&patternList{
  618. newOption("-x", "", 0, false),
  619. newOption("-b", "", 0, false)}, nil)
  620. y = patternList{newOption("-x", "", 0, false)}
  621. z = patternList{newOption("-b", "", 0, false)}
  622. if v != true ||
  623. reflect.DeepEqual(*w, y) != true ||
  624. reflect.DeepEqual(*x, z) != true {
  625. t.Fail()
  626. }
  627. v, w, x = newEither(
  628. newArgument("M", nil),
  629. newRequired(newArgument("N", nil),
  630. newArgument("M", nil))).match(&patternList{
  631. newArgument("", 1),
  632. newArgument("", 2)}, nil)
  633. y = patternList{}
  634. z = patternList{newArgument("N", 1), newArgument("M", 2)}
  635. if v != true ||
  636. reflect.DeepEqual(*w, y) != true ||
  637. reflect.DeepEqual(*x, z) != true {
  638. t.Fail()
  639. }
  640. }
  641. func TestOneOrMoreMatch(t *testing.T) {
  642. v, w, x := newOneOrMore(newArgument("N", nil)).match(
  643. &patternList{newArgument("", 9)}, nil)
  644. y := patternList{newArgument("N", 9)}
  645. if v != true ||
  646. reflect.DeepEqual(*w, patternList{}) != true ||
  647. reflect.DeepEqual(*x, y) != true {
  648. t.Fail()
  649. }
  650. v, w, x = newOneOrMore(newArgument("N", nil)).match(
  651. &patternList{}, nil)
  652. y = patternList{}
  653. z := patternList{}
  654. if v != false ||
  655. reflect.DeepEqual(*w, y) != true ||
  656. reflect.DeepEqual(*x, z) != true {
  657. t.Fail()
  658. }
  659. v, w, x = newOneOrMore(newArgument("N", nil)).match(
  660. &patternList{newOption("-x", "", 0, false)}, nil)
  661. y = patternList{newOption("-x", "", 0, false)}
  662. z = patternList{}
  663. if v != false ||
  664. reflect.DeepEqual(*w, y) != true ||
  665. reflect.DeepEqual(*x, z) != true {
  666. t.Fail()
  667. }
  668. v, w, x = newOneOrMore(newArgument("N", nil)).match(
  669. &patternList{newArgument("", 9), newArgument("", 8)}, nil)
  670. y = patternList{}
  671. z = patternList{newArgument("N", 9), newArgument("N", 8)}
  672. if v != true ||
  673. reflect.DeepEqual(*w, y) != true ||
  674. reflect.DeepEqual(*x, z) != true {
  675. t.Fail()
  676. }
  677. v, w, x = newOneOrMore(newArgument("N", nil)).match(&patternList{
  678. newArgument("", 9),
  679. newOption("-x", "", 0, false),
  680. newArgument("", 8)}, nil)
  681. y = patternList{newOption("-x", "", 0, false)}
  682. z = patternList{newArgument("N", 9), newArgument("N", 8)}
  683. if v != true ||
  684. reflect.DeepEqual(*w, y) != true ||
  685. reflect.DeepEqual(*x, z) != true {
  686. t.Fail()
  687. }
  688. v, w, x = newOneOrMore(newOption("-a", "", 0, false)).match(&patternList{
  689. newOption("-a", "", 0, false),
  690. newArgument("", 8),
  691. newOption("-a", "", 0, false)}, nil)
  692. y = patternList{newArgument("", 8)}
  693. z = patternList{newOption("-a", "", 0, false), newOption("-a", "", 0, false)}
  694. if v != true ||
  695. reflect.DeepEqual(*w, y) != true ||
  696. reflect.DeepEqual(*x, z) != true {
  697. t.Fail()
  698. }
  699. v, w, x = newOneOrMore(newOption("-a", "", 0, false)).match(&patternList{
  700. newArgument("", 8),
  701. newOption("-x", "", 0, false)}, nil)
  702. y = patternList{newArgument("", 8), newOption("-x", "", 0, false)}
  703. z = patternList{}
  704. if v != false ||
  705. reflect.DeepEqual(*w, y) != true ||
  706. reflect.DeepEqual(*x, z) != true {
  707. t.Fail()
  708. }
  709. v, w, x = newOneOrMore(newRequired(newOption("-a", "", 0, false),
  710. newArgument("N", nil))).match(&patternList{
  711. newOption("-a", "", 0, false),
  712. newArgument("", 1),
  713. newOption("-x", "", 0, false),
  714. newOption("-a", "", 0, false),
  715. newArgument("", 2)}, nil)
  716. y = patternList{newOption("-x", "", 0, false)}
  717. z = patternList{newOption("-a", "", 0, false),
  718. newArgument("N", 1),
  719. newOption("-a", "", 0, false),
  720. newArgument("N", 2)}
  721. if v != true ||
  722. reflect.DeepEqual(*w, y) != true ||
  723. reflect.DeepEqual(*x, z) != true {
  724. t.Fail()
  725. }
  726. v, w, x = newOneOrMore(newOptional(newArgument("N", nil))).match(
  727. &patternList{newArgument("", 9)}, nil)
  728. y = patternList{}
  729. z = patternList{newArgument("N", 9)}
  730. if v != true ||
  731. reflect.DeepEqual(*w, y) != true ||
  732. reflect.DeepEqual(*x, z) != true {
  733. t.Fail()
  734. }
  735. }
  736. func TestListArgumentMatch(t *testing.T) {
  737. p := newRequired(
  738. newArgument("N", nil),
  739. newArgument("N", nil))
  740. p.fix()
  741. v, w, x := p.match(&patternList{newArgument("", "1"),
  742. newArgument("", "2")}, nil)
  743. y := patternList{newArgument("N", []string{"1", "2"})}
  744. if v != true ||
  745. reflect.DeepEqual(*w, patternList{}) != true ||
  746. reflect.DeepEqual(*x, y) != true {
  747. t.Fail()
  748. }
  749. p = newOneOrMore(newArgument("N", nil))
  750. p.fix()
  751. v, w, x = p.match(&patternList{newArgument("", "1"),
  752. newArgument("", "2"), newArgument("", "3")}, nil)
  753. y = patternList{newArgument("N", []string{"1", "2", "3"})}
  754. if v != true ||
  755. reflect.DeepEqual(*w, patternList{}) != true ||
  756. reflect.DeepEqual(*x, y) != true {
  757. t.Fail()
  758. }
  759. p = newRequired(newArgument("N", nil),
  760. newOneOrMore(newArgument("N", nil)))
  761. p.fix()
  762. v, w, x = p.match(&patternList{
  763. newArgument("", "1"),
  764. newArgument("", "2"),
  765. newArgument("", "3")}, nil)
  766. y = patternList{newArgument("N", []string{"1", "2", "3"})}
  767. if v != true ||
  768. reflect.DeepEqual(*w, patternList{}) != true ||
  769. reflect.DeepEqual(*x, y) != true {
  770. t.Fail()
  771. }
  772. p = newRequired(newArgument("N", nil),
  773. newRequired(newArgument("N", nil)))
  774. p.fix()
  775. v, w, x = p.match(&patternList{
  776. newArgument("", "1"),
  777. newArgument("", "2")}, nil)
  778. y = patternList{newArgument("N", []string{"1", "2"})}
  779. if v != true ||
  780. reflect.DeepEqual(*w, patternList{}) != true ||
  781. reflect.DeepEqual(*x, y) != true {
  782. t.Fail()
  783. }
  784. }
  785. func TestBasicPatternMatching(t *testing.T) {
  786. // ( -a N [ -x Z ] )
  787. p := newRequired(
  788. newOption("-a", "", 0, false),
  789. newArgument("N", nil),
  790. newOptional(
  791. newOption("-x", "", 0, false),
  792. newArgument("Z", nil)))
  793. // -a N
  794. q := patternList{newOption("-a", "", 0, false), newArgument("", 9)}
  795. y := patternList{newOption("-a", "", 0, false), newArgument("N", 9)}
  796. v, w, x := p.match(&q, nil)
  797. if v != true ||
  798. reflect.DeepEqual(*w, patternList{}) != true ||
  799. reflect.DeepEqual(*x, y) != true {
  800. t.Fail()
  801. }
  802. // -a -x N Z
  803. q = patternList{newOption("-a", "", 0, false),
  804. newOption("-x", "", 0, false),
  805. newArgument("", 9), newArgument("", 5)}
  806. y = patternList{}
  807. z := patternList{newOption("-a", "", 0, false), newArgument("N", 9),
  808. newOption("-x", "", 0, false), newArgument("Z", 5)}
  809. v, w, x = p.match(&q, nil)
  810. if v != true ||
  811. reflect.DeepEqual(*w, y) != true ||
  812. reflect.DeepEqual(*x, z) != true {
  813. t.Fail()
  814. }
  815. // -x N Z # BZZ!
  816. q = patternList{newOption("-x", "", 0, false),
  817. newArgument("", 9), newArgument("", 5)}
  818. y = patternList{newOption("-x", "", 0, false),
  819. newArgument("", 9), newArgument("", 5)}
  820. z = patternList{}
  821. v, w, x = p.match(&q, nil)
  822. if v != false ||
  823. reflect.DeepEqual(*w, y) != true ||
  824. reflect.DeepEqual(*x, z) != true {
  825. t.Fail()
  826. }
  827. }
  828. func TestPatternEither(t *testing.T) {
  829. p := newOption("-a", "", 0, false).transform()
  830. q := newEither(newRequired(
  831. newOption("-a", "", 0, false)))
  832. if p.eq(q) != true {
  833. t.Fail()
  834. }
  835. p = newArgument("A", nil).transform()
  836. q = newEither(newRequired(
  837. newArgument("A", nil)))
  838. if p.eq(q) != true {
  839. t.Fail()
  840. }
  841. p = newRequired(
  842. newEither(
  843. newOption("-a", "", 0, false),
  844. newOption("-b", "", 0, false)),
  845. newOption("-c", "", 0, false)).transform()
  846. q = newEither(
  847. newRequired(
  848. newOption("-a", "", 0, false),
  849. newOption("-c", "", 0, false)),
  850. newRequired(
  851. newOption("-b", "", 0, false),
  852. newOption("-c", "", 0, false)))
  853. if p.eq(q) != true {
  854. t.Fail()
  855. }
  856. p = newOptional(newOption("-a", "", 0, false),
  857. newEither(newOption("-b", "", 0, false),
  858. newOption("-c", "", 0, false))).transform()
  859. q = newEither(
  860. newRequired(
  861. newOption("-b", "", 0, false), newOption("-a", "", 0, false)),
  862. newRequired(
  863. newOption("-c", "", 0, false), newOption("-a", "", 0, false)))
  864. if p.eq(q) != true {
  865. t.Fail()
  866. }
  867. p = newEither(newOption("-x", "", 0, false),
  868. newEither(newOption("-y", "", 0, false),
  869. newOption("-z", "", 0, false))).transform()
  870. q = newEither(
  871. newRequired(newOption("-x", "", 0, false)),
  872. newRequired(newOption("-y", "", 0, false)),
  873. newRequired(newOption("-z", "", 0, false)))
  874. if p.eq(q) != true {
  875. t.Fail()
  876. }
  877. p = newOneOrMore(newArgument("N", nil),
  878. newArgument("M", nil)).transform()
  879. q = newEither(
  880. newRequired(newArgument("N", nil), newArgument("M", nil),
  881. newArgument("N", nil), newArgument("M", nil)))
  882. if p.eq(q) != true {
  883. t.Fail()
  884. }
  885. }
  886. func TestPatternFixRepeatingArguments(t *testing.T) {
  887. p := newOption("-a", "", 0, false)
  888. p.fixRepeatingArguments()
  889. if p.eq(newOption("-a", "", 0, false)) != true {
  890. t.Fail()
  891. }
  892. p = newArgument("N", nil)
  893. p.fixRepeatingArguments()
  894. if p.eq(newArgument("N", nil)) != true {
  895. t.Fail()
  896. }
  897. p = newRequired(
  898. newArgument("N", nil),
  899. newArgument("N", nil))
  900. q := newRequired(
  901. newArgument("N", []string{}),
  902. newArgument("N", []string{}))
  903. p.fixRepeatingArguments()
  904. if p.eq(q) != true {
  905. t.Fail()
  906. }
  907. p = newEither(
  908. newArgument("N", nil),
  909. newOneOrMore(newArgument("N", nil)))
  910. q = newEither(
  911. newArgument("N", []string{}),
  912. newOneOrMore(newArgument("N", []string{})))
  913. p.fix()
  914. if p.eq(q) != true {
  915. t.Fail()
  916. }
  917. }
  918. func TestSet(t *testing.T) {
  919. p := newArgument("N", nil)
  920. q := newArgument("N", nil)
  921. if reflect.DeepEqual(p, q) != true {
  922. t.Fail()
  923. }
  924. pl := patternList{newArgument("N", nil), newArgument("N", nil)}
  925. ql := patternList{newArgument("N", nil)}
  926. if reflect.DeepEqual(pl.unique(), ql.unique()) != true {
  927. t.Fail()
  928. }
  929. }
  930. func TestPatternFixIdentities1(t *testing.T) {
  931. p := newRequired(
  932. newArgument("N", nil),
  933. newArgument("N", nil))
  934. if len(p.children) < 2 {
  935. t.FailNow()
  936. }
  937. if p.children[0].eq(p.children[1]) != true {
  938. t.Fail()
  939. }
  940. if p.children[0] == p.children[1] {
  941. t.Fail()
  942. }
  943. p.fixIdentities(nil)
  944. if p.children[0] != p.children[1] {
  945. t.Fail()
  946. }
  947. }
  948. func TestPatternFixIdentities2(t *testing.T) {
  949. p := newRequired(
  950. newOptional(
  951. newArgument("X", nil),
  952. newArgument("N", nil)),
  953. newArgument("N", nil))
  954. if len(p.children) < 2 {
  955. t.FailNow()
  956. }
  957. if len(p.children[0].children) < 2 {
  958. t.FailNow()
  959. }
  960. if p.children[0].children[1].eq(p.children[1]) != true {
  961. t.Fail()
  962. }
  963. if p.children[0].children[1] == p.children[1] {
  964. t.Fail()
  965. }
  966. p.fixIdentities(nil)
  967. if p.children[0].children[1] != p.children[1] {
  968. t.Fail()
  969. }
  970. }
  971. func TestLongOptionsErrorHandling(t *testing.T) {
  972. _, err := Parse("Usage: prog", []string{"--non-existent"}, true, "", false, false)
  973. if _, ok := err.(*UserError); !ok {
  974. t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err))
  975. }
  976. _, err = Parse("Usage: prog [--version --verbose]\nOptions: --version\n --verbose",
  977. []string{"--ver"}, true, "", false, false)
  978. if _, ok := err.(*UserError); !ok {
  979. t.Error(err)
  980. }
  981. _, err = Parse("Usage: prog --long\nOptions: --long ARG", []string{}, true, "", false, false)
  982. if _, ok := err.(*LanguageError); !ok {
  983. t.Error(err)
  984. }
  985. _, err = Parse("Usage: prog --long ARG\nOptions: --long ARG",
  986. []string{"--long"}, true, "", false, false)
  987. if _, ok := err.(*UserError); !ok {
  988. t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err))
  989. }
  990. _, err = Parse("Usage: prog --long=ARG\nOptions: --long", []string{}, true, "", false, false)
  991. if _, ok := err.(*LanguageError); !ok {
  992. t.Error(err)
  993. }
  994. _, err = Parse("Usage: prog --long\nOptions: --long",
  995. []string{}, true, "--long=ARG", false, false)
  996. if _, ok := err.(*UserError); !ok {
  997. t.Error(err)
  998. }
  999. }
  1000. func TestShortOptionsErrorHandling(t *testing.T) {
  1001. _, err := Parse("Usage: prog -x\nOptions: -x this\n -x that", []string{}, true, "", false, false)
  1002. if _, ok := err.(*LanguageError); !ok {
  1003. t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err))
  1004. }
  1005. _, err = Parse("Usage: prog", []string{"-x"}, true, "", false, false)
  1006. if _, ok := err.(*UserError); !ok {
  1007. t.Error(err)
  1008. }
  1009. _, err = Parse("Usage: prog -o\nOptions: -o ARG", []string{}, true, "", false, false)
  1010. if _, ok := err.(*LanguageError); !ok {
  1011. t.Error(err)
  1012. }
  1013. _, err = Parse("Usage: prog -o ARG\nOptions: -o ARG", []string{"-o"}, true, "", false, false)
  1014. if _, ok := err.(*UserError); !ok {
  1015. t.Error(err)
  1016. }
  1017. }
  1018. func TestMatchingParen(t *testing.T) {
  1019. _, err := Parse("Usage: prog [a [b]", []string{}, true, "", false, false)
  1020. if _, ok := err.(*LanguageError); !ok {
  1021. t.Error(err)
  1022. }
  1023. _, err = Parse("Usage: prog [a [b] ] c )", []string{}, true, "", false, false)
  1024. if _, ok := err.(*LanguageError); !ok {
  1025. t.Error(err)
  1026. }
  1027. }
  1028. func TestAllowDoubleDash(t *testing.T) {
  1029. if v, err := Parse("usage: prog [-o] [--] <arg>\noptions: -o", []string{"--", "-o"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-o": false, "<arg>": "-o", "--": true}) != true {
  1030. t.Error(err)
  1031. }
  1032. if v, err := Parse("usage: prog [-o] [--] <arg>\noptions: -o", []string{"-o", "1"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-o": true, "<arg>": "1", "--": false}) != true {
  1033. t.Error(err)
  1034. }
  1035. _, err := Parse("usage: prog [-o] <arg>\noptions:-o", []string{"-o"}, true, "", false, false)
  1036. if _, ok := err.(*UserError); !ok { //"--" is not allowed; FIXME?
  1037. t.Error(err)
  1038. }
  1039. }
  1040. func TestDocopt(t *testing.T) {
  1041. doc := `Usage: prog [-v] A
  1042. Options: -v Be verbose.`
  1043. if v, err := Parse(doc, []string{"arg"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": false, "A": "arg"}) != true {
  1044. t.Error(err)
  1045. }
  1046. if v, err := Parse(doc, []string{"-v", "arg"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": true, "A": "arg"}) != true {
  1047. t.Error(err)
  1048. }
  1049. doc = `Usage: prog [-vqr] [FILE]
  1050. prog INPUT OUTPUT
  1051. prog --help
  1052. Options:
  1053. -v print status messages
  1054. -q report only file names
  1055. -r show all occurrences of the same error
  1056. --help
  1057. `
  1058. if v, err := Parse(doc, []string{"-v", "file.py"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": true, "-q": false, "-r": false, "--help": false, "FILE": "file.py", "INPUT": nil, "OUTPUT": nil}) != true {
  1059. t.Error(err)
  1060. }
  1061. if v, err := Parse(doc, []string{"-v"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": true, "-q": false, "-r": false, "--help": false, "FILE": nil, "INPUT": nil, "OUTPUT": nil}) != true {
  1062. t.Error(err)
  1063. }
  1064. _, err := Parse(doc, []string{"-v", "input.py", "output.py"}, true, "", false, false) // does not match
  1065. if _, ok := err.(*UserError); !ok {
  1066. t.Error(err)
  1067. }
  1068. _, err = Parse(doc, []string{"--fake"}, true, "", false, false)
  1069. if _, ok := err.(*UserError); !ok {
  1070. t.Error(err)
  1071. }
  1072. _, output, err := parseOutput(doc, []string{"--hel"}, true, "", false)
  1073. if err != nil || len(output) == 0 {
  1074. t.Error(err)
  1075. }
  1076. }
  1077. func TestLanguageErrors(t *testing.T) {
  1078. _, err := Parse("no usage with colon here", []string{}, true, "", false, false)
  1079. if _, ok := err.(*LanguageError); !ok {
  1080. t.Error(err)
  1081. }
  1082. _, err = Parse("usage: here \n\n and again usage: here", []string{}, true, "", false, false)
  1083. if _, ok := err.(*LanguageError); !ok {
  1084. t.Error(err)
  1085. }
  1086. }
  1087. func TestIssue40(t *testing.T) {
  1088. _, output, err := parseOutput("usage: prog --help-commands | --help", []string{"--help"}, true, "", false)
  1089. if err != nil || len(output) == 0 {
  1090. t.Error(err)
  1091. }
  1092. if v, err := Parse("usage: prog --aabb | --aa", []string{"--aa"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--aabb": false, "--aa": true}) != true {
  1093. t.Error(err)
  1094. }
  1095. }
  1096. func TestIssue34UnicodeStrings(t *testing.T) {
  1097. // TODO: see if applicable
  1098. }
  1099. func TestCountMultipleFlags(t *testing.T) {
  1100. if v, err := Parse("usage: prog [-v]", []string{"-v"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": true}) != true {
  1101. t.Error(err)
  1102. }
  1103. if v, err := Parse("usage: prog [-vv]", []string{}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 0}) != true {
  1104. t.Error(err)
  1105. }
  1106. if v, err := Parse("usage: prog [-vv]", []string{"-v"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 1}) != true {
  1107. t.Error(err)
  1108. }
  1109. if v, err := Parse("usage: prog [-vv]", []string{"-vv"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 2}) != true {
  1110. t.Error(err)
  1111. }
  1112. _, err := Parse("usage: prog [-vv]", []string{"-vvv"}, true, "", false, false)
  1113. if _, ok := err.(*UserError); !ok {
  1114. t.Error(err)
  1115. }
  1116. if v, err := Parse("usage: prog [-v | -vv | -vvv]", []string{"-vvv"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 3}) != true {
  1117. t.Error(err)
  1118. }
  1119. if v, err := Parse("usage: prog [-v...]", []string{"-vvvvvv"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 6}) != true {
  1120. t.Error(err)
  1121. }
  1122. if v, err := Parse("usage: prog [--ver --ver]", []string{"--ver", "--ver"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--ver": 2}) != true {
  1123. t.Error(err)
  1124. }
  1125. }
  1126. func TestAnyOptionsParameter(t *testing.T) {
  1127. _, err := Parse("usage: prog [options]",
  1128. []string{"-foo", "--bar", "--spam=eggs"}, true, "", false, false)
  1129. if _, ok := err.(*UserError); !ok {
  1130. t.Fail()
  1131. }
  1132. _, err = Parse("usage: prog [options]",
  1133. []string{"--foo", "--bar", "--bar"}, true, "", false, false)
  1134. if _, ok := err.(*UserError); !ok {
  1135. t.Fail()
  1136. }
  1137. _, err = Parse("usage: prog [options]",
  1138. []string{"--bar", "--bar", "--bar", "-ffff"}, true, "", false, false)
  1139. if _, ok := err.(*UserError); !ok {
  1140. t.Fail()
  1141. }
  1142. _, err = Parse("usage: prog [options]",
  1143. []string{"--long=arg", "--long=another"}, true, "", false, false)
  1144. if _, ok := err.(*UserError); !ok {
  1145. t.Fail()
  1146. }
  1147. }
  1148. func TestDefaultValueForPositionalArguments(t *testing.T) {
  1149. doc := "Usage: prog [--data=<data>...]\nOptions:\n\t-d --data=<arg> Input data [default: x]"
  1150. if v, err := Parse(doc, []string{}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--data": []string{"x"}}) != true {
  1151. t.Error(err)
  1152. }
  1153. doc = "Usage: prog [--data=<data>...]\nOptions:\n\t-d --data=<arg> Input data [default: x y]"
  1154. if v, err := Parse(doc, []string{}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--data": []string{"x", "y"}}) != true {
  1155. t.Error(err)
  1156. }
  1157. doc = "Usage: prog [--data=<data>...]\nOptions:\n\t-d --data=<arg> Input data [default: x y]"
  1158. if v, err := Parse(doc, []string{"--data=this"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--data": []string{"this"}}) != true {
  1159. t.Error(err)
  1160. }
  1161. }
  1162. func TestIssue59(t *testing.T) {
  1163. if v, err := Parse("usage: prog --long=<a>", []string{"--long="}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--long": ""}) != true {
  1164. t.Error(err)
  1165. }
  1166. if v, err := Parse("usage: prog -l <a>\noptions: -l <a>", []string{"-l", ""}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-l": ""}) != true {
  1167. t.Error(err)
  1168. }
  1169. }
  1170. func TestOptionsFirst(t *testing.T) {
  1171. if v, err := Parse("usage: prog [--opt] [<args>...]", []string{"--opt", "this", "that"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--opt": true, "<args>": []string{"this", "that"}}) != true {
  1172. t.Error(err)
  1173. }
  1174. if v, err := Parse("usage: prog [--opt] [<args>...]", []string{"this", "that", "--opt"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--opt": true, "<args>": []string{"this", "that"}}) != true {
  1175. t.Error(err)
  1176. }
  1177. if v, err := Parse("usage: prog [--opt] [<args>...]", []string{"this", "that", "--opt"}, true, "", true, false); reflect.DeepEqual(v, map[string]interface{}{"--opt": false, "<args>": []string{"this", "that", "--opt"}}) != true {
  1178. t.Error(err)
  1179. }
  1180. }
  1181. func TestIssue68OptionsShortcutDoesNotIncludeOptionsInUsagePattern(t *testing.T) {
  1182. args, err := Parse("usage: prog [-ab] [options]\noptions: -x\n -y", []string{"-ax"}, true, "", false, false)
  1183. if args["-a"] != true {
  1184. t.Error(err)
  1185. }
  1186. if args["-b"] != false {
  1187. t.Error(err)
  1188. }
  1189. if args["-x"] != true {
  1190. t.Error(err)
  1191. }
  1192. if args["-y"] != false {
  1193. t.Error(err)
  1194. }
  1195. }
  1196. func TestIssue65EvaluateArgvWhenCalledNotWhenImported(t *testing.T) {
  1197. os.Args = strings.Fields("prog -a")
  1198. v, err := Parse("usage: prog [-ab]", nil, true, "", false, false)
  1199. w := map[string]interface{}{"-a": true, "-b": false}
  1200. if reflect.DeepEqual(v, w) != true {
  1201. t.Error(err)
  1202. }
  1203. os.Args = strings.Fields("prog -b")
  1204. v, err = Parse("usage: prog [-ab]", nil, true, "", false, false)
  1205. w = map[string]interface{}{"-a": false, "-b": true}
  1206. if reflect.DeepEqual(v, w) != true {
  1207. t.Error(err)
  1208. }
  1209. }
  1210. func TestIssue71DoubleDashIsNotAValidOptionArgument(t *testing.T) {
  1211. _, err := Parse("usage: prog [--log=LEVEL] [--] <args>...",
  1212. []string{"--log", "--", "1", "2"}, true, "", false, false)
  1213. if _, ok := err.(*UserError); !ok {
  1214. t.Fail()
  1215. }
  1216. _, err = Parse(`usage: prog [-l LEVEL] [--] <args>...
  1217. options: -l LEVEL`, []string{"-l", "--", "1", "2"}, true, "", false, false)
  1218. if _, ok := err.(*UserError); !ok {
  1219. t.Fail()
  1220. }
  1221. }
  1222. func TestParseSection(t *testing.T) {
  1223. v := parseSection("usage:", "foo bar fizz buzz")
  1224. w := []string{}
  1225. if reflect.DeepEqual(v, w) != true {
  1226. t.Fail()
  1227. }
  1228. v = parseSection("usage:", "usage: prog")
  1229. w = []string{"usage: prog"}
  1230. if reflect.DeepEqual(v, w) != true {
  1231. t.Fail()
  1232. }
  1233. v = parseSection("usage:", "usage: -x\n -y")
  1234. w = []string{"usage: -x\n -y"}
  1235. if reflect.DeepEqual(v, w) != true {
  1236. t.Fail()
  1237. }
  1238. usage := `usage: this
  1239. usage:hai
  1240. usage: this that
  1241. usage: foo
  1242. bar
  1243. PROGRAM USAGE:
  1244. foo
  1245. bar
  1246. usage:
  1247. ` + "\t" + `too
  1248. ` + "\t" + `tar
  1249. Usage: eggs spam
  1250. BAZZ
  1251. usage: pit stop`
  1252. v = parseSection("usage:", usage)
  1253. w = []string{"usage: this",
  1254. "usage:hai",
  1255. "usage: this that",
  1256. "usage: foo\n bar",
  1257. "PROGRAM USAGE:\n foo\n bar",
  1258. "usage:\n\ttoo\n\ttar",
  1259. "Usage: eggs spam",
  1260. "usage: pit stop",
  1261. }
  1262. if reflect.DeepEqual(v, w) != true {
  1263. t.Fail()
  1264. }
  1265. }
  1266. func TestIssue126DefaultsNotParsedCorrectlyWhenTabs(t *testing.T) {
  1267. section := "Options:\n\t--foo=<arg> [default: bar]"
  1268. v := patternList{newOption("", "--foo", 1, "bar")}
  1269. if reflect.DeepEqual(parseDefaults(section), v) != true {
  1270. t.Fail()
  1271. }
  1272. }
  1273. // conf file based test cases
  1274. func TestFileTestcases(t *testing.T) {
  1275. filenames := []string{"testcases.docopt", "test_golang.docopt"}
  1276. for _, filename := range filenames {
  1277. raw, err := ioutil.ReadFile(filename)
  1278. if err != nil {
  1279. t.Fatal(err)
  1280. }
  1281. tests, err := parseTest(raw)
  1282. if err != nil {
  1283. t.Fatal(err)
  1284. }
  1285. for _, c := range tests {
  1286. result, err := Parse(c.doc, c.argv, true, "", false, false)
  1287. if _, ok := err.(*UserError); c.userError && !ok {
  1288. // expected a user-error
  1289. t.Error("testcase:", c.id, "result:", result)
  1290. } else if _, ok := err.(*UserError); !c.userError && ok {
  1291. // unexpected user-error
  1292. t.Error("testcase:", c.id, "error:", err, "result:", result)
  1293. } else if reflect.DeepEqual(c.expect, result) != true {
  1294. t.Error("testcase:", c.id, "result:", result, "expect:", c.expect)
  1295. }
  1296. }
  1297. }
  1298. }
  1299. type testcase struct {
  1300. id int
  1301. doc string
  1302. prog string
  1303. argv []string
  1304. expect map[string]interface{}
  1305. userError bool
  1306. }
  1307. func parseTest(raw []byte) ([]testcase, error) {
  1308. var res []testcase
  1309. commentPattern := regexp.MustCompile("#.*")
  1310. raw = commentPattern.ReplaceAll(raw, []byte(""))
  1311. raw = bytes.TrimSpace(raw)
  1312. if bytes.HasPrefix(raw, []byte(`"""`)) {
  1313. raw = raw[3:]
  1314. }
  1315. id := 0
  1316. for _, fixture := range bytes.Split(raw, []byte(`r"""`)) {
  1317. doc, _, body := stringPartition(string(fixture), `"""`)
  1318. for _, cas := range strings.Split(body, "$")[1:] {
  1319. argvString, _, expectString := stringPartition(strings.TrimSpace(cas), "\n")
  1320. prog, _, argvString := stringPartition(strings.TrimSpace(argvString), " ")
  1321. argv := []string{}
  1322. if len(argvString) > 0 {
  1323. argv = strings.Fields(argvString)
  1324. }
  1325. var expectUntyped interface{}
  1326. err := json.Unmarshal([]byte(expectString), &expectUntyped)
  1327. if err != nil {
  1328. return nil, err
  1329. }
  1330. switch expect := expectUntyped.(type) {
  1331. case string: // user-error
  1332. res = append(res, testcase{id, doc, prog, argv, nil, true})
  1333. case map[string]interface{}:
  1334. // convert []interface{} values to []string
  1335. // convert float64 values to int
  1336. for k, vUntyped := range expect {
  1337. switch v := vUntyped.(type) {
  1338. case []interface{}:
  1339. itemList := make([]string, len(v))
  1340. for i, itemUntyped := range v {
  1341. if item, ok := itemUntyped.(string); ok {
  1342. itemList[i] = item
  1343. }
  1344. }
  1345. expect[k] = itemList
  1346. case float64:
  1347. expect[k] = int(v)
  1348. }
  1349. }
  1350. res = append(res, testcase{id, doc, prog, argv, expect, false})
  1351. default:
  1352. return nil, fmt.Errorf("unhandled json data type")
  1353. }
  1354. id++
  1355. }
  1356. }
  1357. return res, nil
  1358. }
  1359. // parseOutput wraps the Parse() function to also return stdout
  1360. func parseOutput(doc string, argv []string, help bool, version string,
  1361. optionsFirst bool) (map[string]interface{}, string, error) {
  1362. stdout := os.Stdout
  1363. r, w, _ := os.Pipe()
  1364. os.Stdout = w
  1365. args, err := Parse(doc, argv, help, version, optionsFirst, false)
  1366. outChan := make(chan string)
  1367. go func() {
  1368. var buf bytes.Buffer
  1369. io.Copy(&buf, r)
  1370. outChan <- buf.String()
  1371. }()
  1372. w.Close()
  1373. os.Stdout = stdout
  1374. output := <-outChan
  1375. return args, output, err
  1376. }
  1377. var debugEnabled = false
  1378. func debugOn(l ...interface{}) {
  1379. debugEnabled = true
  1380. debug(l...)
  1381. }
  1382. func debugOff(l ...interface{}) {
  1383. debug(l...)
  1384. debugEnabled = false
  1385. }
  1386. func debug(l ...interface{}) {
  1387. if debugEnabled {
  1388. fmt.Println(l...)
  1389. }
  1390. }