2
0

ini_parser_test.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. // +build go1.7
  2. package ini
  3. import (
  4. "bytes"
  5. "fmt"
  6. "io"
  7. "reflect"
  8. "testing"
  9. )
  10. func TestParser(t *testing.T) {
  11. xID, _, _ := newLitToken([]rune("x = 1234"))
  12. s3ID, _, _ := newLitToken([]rune("s3 = 1234"))
  13. fooSlashes, _, _ := newLitToken([]rune("//foo"))
  14. regionID, _, _ := newLitToken([]rune("region"))
  15. regionLit, _, _ := newLitToken([]rune(`"us-west-2"`))
  16. regionNoQuotesLit, _, _ := newLitToken([]rune("us-west-2"))
  17. credentialID, _, _ := newLitToken([]rune("credential_source"))
  18. ec2MetadataLit, _, _ := newLitToken([]rune("Ec2InstanceMetadata"))
  19. outputID, _, _ := newLitToken([]rune("output"))
  20. outputLit, _, _ := newLitToken([]rune("json"))
  21. equalOp, _, _ := newOpToken([]rune("= 1234"))
  22. equalColonOp, _, _ := newOpToken([]rune(": 1234"))
  23. numLit, _, _ := newLitToken([]rune("1234"))
  24. defaultID, _, _ := newLitToken([]rune("default"))
  25. assumeID, _, _ := newLitToken([]rune("assumerole"))
  26. defaultProfileStmt := newSectionStatement(defaultID)
  27. assumeProfileStmt := newSectionStatement(assumeID)
  28. fooSlashesExpr := newExpression(fooSlashes)
  29. xEQ1234 := newEqualExpr(newExpression(xID), equalOp)
  30. xEQ1234.AppendChild(newExpression(numLit))
  31. xEQColon1234 := newEqualExpr(newExpression(xID), equalColonOp)
  32. xEQColon1234.AppendChild(newExpression(numLit))
  33. regionEQRegion := newEqualExpr(newExpression(regionID), equalOp)
  34. regionEQRegion.AppendChild(newExpression(regionLit))
  35. noQuotesRegionEQRegion := newEqualExpr(newExpression(regionID), equalOp)
  36. noQuotesRegionEQRegion.AppendChild(newExpression(regionNoQuotesLit))
  37. credEQExpr := newEqualExpr(newExpression(credentialID), equalOp)
  38. credEQExpr.AppendChild(newExpression(ec2MetadataLit))
  39. outputEQExpr := newEqualExpr(newExpression(outputID), equalOp)
  40. outputEQExpr.AppendChild(newExpression(outputLit))
  41. cases := []struct {
  42. name string
  43. r io.Reader
  44. expectedStack []AST
  45. expectedError bool
  46. }{
  47. {
  48. name: "semicolon comment",
  49. r: bytes.NewBuffer([]byte(`;foo`)),
  50. expectedStack: []AST{
  51. newCommentStatement(newToken(TokenComment, []rune(";foo"), NoneType)),
  52. },
  53. },
  54. {
  55. name: "0==0",
  56. r: bytes.NewBuffer([]byte(`0==0`)),
  57. expectedError: true,
  58. },
  59. {
  60. name: "0=:0",
  61. r: bytes.NewBuffer([]byte(`0=:0`)),
  62. expectedError: true,
  63. },
  64. {
  65. name: "0:=0",
  66. r: bytes.NewBuffer([]byte(`0:=0`)),
  67. expectedError: true,
  68. },
  69. {
  70. name: "0::0",
  71. r: bytes.NewBuffer([]byte(`0::0`)),
  72. expectedError: true,
  73. },
  74. {
  75. name: "section with variable",
  76. r: bytes.NewBuffer([]byte(`[ default ]x`)),
  77. expectedStack: []AST{
  78. newCompletedSectionStatement(
  79. defaultProfileStmt,
  80. ),
  81. newExpression(xID),
  82. },
  83. },
  84. {
  85. name: "# comment",
  86. r: bytes.NewBuffer([]byte(`# foo`)),
  87. expectedStack: []AST{
  88. newCommentStatement(newToken(TokenComment, []rune("# foo"), NoneType)),
  89. },
  90. },
  91. {
  92. name: "// not a comment",
  93. r: bytes.NewBuffer([]byte(`//foo`)),
  94. expectedStack: []AST{
  95. fooSlashesExpr,
  96. },
  97. },
  98. {
  99. name: "multiple comments",
  100. r: bytes.NewBuffer([]byte(`;foo
  101. # baz
  102. `)),
  103. expectedStack: []AST{
  104. newCommentStatement(newToken(TokenComment, []rune(";foo"), NoneType)),
  105. newCommentStatement(newToken(TokenComment, []rune("# baz"), NoneType)),
  106. },
  107. },
  108. {
  109. name: "comment followed by skip state",
  110. r: bytes.NewBuffer([]byte(`;foo
  111. //foo
  112. # baz
  113. `)),
  114. expectedStack: []AST{
  115. newCommentStatement(newToken(TokenComment, []rune(";foo"), NoneType)),
  116. },
  117. },
  118. {
  119. name: "assignment",
  120. r: bytes.NewBuffer([]byte(`x = 1234`)),
  121. expectedStack: []AST{
  122. newExprStatement(xEQ1234),
  123. },
  124. },
  125. {
  126. name: "assignment spaceless",
  127. r: bytes.NewBuffer([]byte(`x=1234`)),
  128. expectedStack: []AST{
  129. newExprStatement(xEQ1234),
  130. },
  131. },
  132. {
  133. name: "assignment :",
  134. r: bytes.NewBuffer([]byte(`x : 1234`)),
  135. expectedStack: []AST{
  136. newExprStatement(xEQColon1234),
  137. },
  138. },
  139. {
  140. name: "assignment : no spaces",
  141. r: bytes.NewBuffer([]byte(`x:1234`)),
  142. expectedStack: []AST{
  143. newExprStatement(xEQColon1234),
  144. },
  145. },
  146. {
  147. name: "section expression",
  148. r: bytes.NewBuffer([]byte(`[ default ]`)),
  149. expectedStack: []AST{
  150. newCompletedSectionStatement(
  151. defaultProfileStmt,
  152. ),
  153. },
  154. },
  155. {
  156. name: "section expression no spaces",
  157. r: bytes.NewBuffer([]byte(`[default]`)),
  158. expectedStack: []AST{
  159. newCompletedSectionStatement(
  160. defaultProfileStmt,
  161. ),
  162. },
  163. },
  164. {
  165. name: "section statement",
  166. r: bytes.NewBuffer([]byte(`[default]
  167. region="us-west-2"`)),
  168. expectedStack: []AST{
  169. newCompletedSectionStatement(
  170. defaultProfileStmt,
  171. ),
  172. newExprStatement(regionEQRegion),
  173. },
  174. },
  175. {
  176. name: "complex section statement",
  177. r: bytes.NewBuffer([]byte(`[default]
  178. region = us-west-2
  179. credential_source = Ec2InstanceMetadata
  180. output = json
  181. [assumerole]
  182. output = json
  183. region = us-west-2
  184. `)),
  185. expectedStack: []AST{
  186. newCompletedSectionStatement(
  187. defaultProfileStmt,
  188. ),
  189. newExprStatement(noQuotesRegionEQRegion),
  190. newExprStatement(credEQExpr),
  191. newExprStatement(outputEQExpr),
  192. newCompletedSectionStatement(
  193. assumeProfileStmt,
  194. ),
  195. newExprStatement(outputEQExpr),
  196. newExprStatement(noQuotesRegionEQRegion),
  197. },
  198. },
  199. {
  200. name: "complex section statement with nested params",
  201. r: bytes.NewBuffer([]byte(`[default]
  202. s3 =
  203. foo=bar
  204. bar=baz
  205. region = us-west-2
  206. credential_source = Ec2InstanceMetadata
  207. output = json
  208. [assumerole]
  209. output = json
  210. region = us-west-2
  211. `)),
  212. expectedStack: []AST{
  213. newCompletedSectionStatement(
  214. defaultProfileStmt,
  215. ),
  216. newSkipStatement(newEqualExpr(newExpression(s3ID), equalOp)),
  217. newExprStatement(noQuotesRegionEQRegion),
  218. newExprStatement(credEQExpr),
  219. newExprStatement(outputEQExpr),
  220. newCompletedSectionStatement(
  221. assumeProfileStmt,
  222. ),
  223. newExprStatement(outputEQExpr),
  224. newExprStatement(noQuotesRegionEQRegion),
  225. },
  226. },
  227. {
  228. name: "complex section statement",
  229. r: bytes.NewBuffer([]byte(`[default]
  230. region = us-west-2
  231. credential_source = Ec2InstanceMetadata
  232. s3 =
  233. foo=bar
  234. bar=baz
  235. output = json
  236. [assumerole]
  237. output = json
  238. region = us-west-2
  239. `)),
  240. expectedStack: []AST{
  241. newCompletedSectionStatement(
  242. defaultProfileStmt,
  243. ),
  244. newExprStatement(noQuotesRegionEQRegion),
  245. newExprStatement(credEQExpr),
  246. newSkipStatement(newEqualExpr(newExpression(s3ID), equalOp)),
  247. newExprStatement(outputEQExpr),
  248. newCompletedSectionStatement(
  249. assumeProfileStmt,
  250. ),
  251. newExprStatement(outputEQExpr),
  252. newExprStatement(noQuotesRegionEQRegion),
  253. },
  254. },
  255. }
  256. for i, c := range cases {
  257. t.Run(c.name, func(t *testing.T) {
  258. stack, err := ParseAST(c.r)
  259. if e, a := c.expectedError, err != nil; e != a {
  260. t.Errorf("%d: expected %t, but received %t with error %v", i, e, a, err)
  261. }
  262. if e, a := len(c.expectedStack), len(stack); e != a {
  263. t.Errorf("expected same length %d, but received %d", e, a)
  264. }
  265. if e, a := c.expectedStack, stack; !reflect.DeepEqual(e, a) {
  266. buf := bytes.Buffer{}
  267. buf.WriteString("expected:\n")
  268. for j := 0; j < len(e); j++ {
  269. buf.WriteString(fmt.Sprintf("\t%d: %v\n", j, e[j]))
  270. }
  271. buf.WriteString("\nreceived:\n")
  272. for j := 0; j < len(a); j++ {
  273. buf.WriteString(fmt.Sprintf("\t%d: %v\n", j, a[j]))
  274. }
  275. t.Errorf("%s", buf.String())
  276. }
  277. })
  278. }
  279. }