content: module Test.Language.Javascript.RoundTrip
      ( testRoundTrip
      ) where
  
  import Test.Hspec
  
  import Language.JavaScript.Parser
  import qualified Language.JavaScript.Parser.AST as AST
  
  
  testRoundTrip :: Spec
  testRoundTrip = describe "Roundtrip:" $ do
      it "multi comment" $ do
          testRT "/*a*/\n//foo\nnull"
          testRT "/*a*/x"
          testRT "/*a*/null"
          testRT "/*b*/false"
          testRT "true/*c*/"
          testRT "/*c*/true"
          testRT "/*d*/0x1234fF"
          testRT "/*e*/1.0e4"
          testRT "/*x*/011"
          testRT "/*f*/\"hello\\nworld\""
          testRT "/*g*/'hello\\nworld'"
          testRT "/*h*/this"
          testRT "/*i*//blah/"
          testRT "//j\nthis_"
  
      it "arrays" $ do
          testRT "/*a*/[/*b*/]"
          testRT "/*a*/[/*b*/,/*c*/]"
          testRT "/*a*/[/*b*/,/*c*/,/*d*/]"
          testRT "/*a*/[/*b/*,/*c*/,/*d*/x/*e*/]"
          testRT "/*a*/[/*b*/,/*c*/,/*d*/x/*e*/]"
          testRT "/*a*/[/*b*/,/*c*/x/*d*/,/*e*/,/*f*/x/*g*/]"
          testRT "/*a*/[/*b*/x/*c*/]"
          testRT "/*a*/[/*b*/x/*c*/,/*d*/]"
  
      it "object literals" $ do
          testRT "/*a*/{/*b*/}"
          testRT "/*a*/{/*b*/x/*c*/:/*d*/1/*e*/}"
          testRT "/*a*/{/*b*/x/*c*/}"
          testRT "/*a*/{/*b*/of/*c*/}"
          testRT "x=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/y/*g*/:/*h*/2/*i*/}"
          testRT "x=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/y/*g*/:/*h*/2/*i*/,/*j*/z/*k*/:/*l*/3/*m*/}"
          testRT "a=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/}"
          testRT "/*a*/{/*b*/[/*c*/x/*d*/+/*e*/y/*f*/]/*g*/:/*h*/1/*i*/}"
          testRT "/*a*/{/*b*/a/*c*/(/*d*/x/*e*/,/*f*/y/*g*/)/*h*/{/*i*/}/*j*/}"
          testRT "/*a*/{/*b*/[/*c*/x/*d*/+/*e*/y/*f*/]/*g*/(/*h*/)/*i*/{/*j*/}/*k*/}"
          testRT "/*a*/{/*b*/*/*c*/a/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/}"
  
      it "miscellaneous" $ do
          testRT "/*a*/(/*b*/56/*c*/)"
          testRT "/*a*/true/*b*/?/*c*/1/*d*/:/*e*/2"
          testRT "/*a*/x/*b*/||/*c*/y"
          testRT "/*a*/x/*b*/&&/*c*/y"
          testRT "/*a*/x/*b*/|/*c*/y"
          testRT "/*a*/x/*b*/^/*c*/y"
          testRT "/*a*/x/*b*/&/*c*/y"
          testRT "/*a*/x/*b*/==/*c*/y"
          testRT "/*a*/x/*b*/!=/*c*/y"
          testRT "/*a*/x/*b*/===/*c*/y"
          testRT "/*a*/x/*b*/!==/*c*/y"
          testRT "/*a*/x/*b*/</*c*/y"
          testRT "/*a*/x/*b*/>/*c*/y"
          testRT "/*a*/x/*b*/<=/*c*/y"
          testRT "/*a*/x/*b*/>=/*c*/y"
          testRT "/*a*/x /*b*/instanceof /*c*/y"
          testRT "/*a*/x/*b*/=/*c*/{/*d*/get/*e*/ foo/*f*/(/*g*/)/*h*/ {/*i*/return/*j*/ 1/*k*/}/*l*/,/*m*/set/*n*/ foo/*o*/(/*p*/a/*q*/) /*r*/{/*s*/x/*t*/=/*u*/a/*v*/}/*w*/}"
          testRT "x = { set foo(/*a*/[/*b*/a/*c*/,/*d*/b/*e*/]/*f*/=/*g*/y/*h*/) {} }"
          testRT "... /*a*/ x"
  
          testRT "a => {}"
          testRT "(a) => { a + 2 }"
          testRT "(a, b) => {}"
          testRT "(a, b) => a + b"
          testRT "() => { 42 }"
          testRT "(...a) => a"
          testRT "(a=1, b=2) => a + b"
          testRT "([a, b]) => a + b"
          testRT "({a, b}) => a + b"
  
          testRT "function (...a) {}"
          testRT "function (a=1, b=2) {}"
          testRT "function ([a, ...b]) {}"
          testRT "function ({a, b: c}) {}"
  
          testRT "/*a*/function/*b*/*/*c*/f/*d*/(/*e*/)/*f*/{/*g*/yield/*h*/a/*i*/}/*j*/"
          testRT "function*(a, b) { yield a ; yield b ; }"
  
          testRT "/*a*/`<${/*b*/x/*c*/}>`/*d*/"
          testRT "`\\${}`"
          testRT "`\n\n`"
          testRT "{}+``"
          -- ^ https://github.com/erikd/language-javascript/issues/104
  
  
      it "statement" $ do
          testRT "if (1) {}"
          testRT "if (1) {} else {}"
          testRT "if (1) x=1; else {}"
          testRT "do {x=1} while (true);"
          testRT "do x=x+1;while(x<4);"
          testRT "while(true);"
          testRT "for(;;);"
          testRT "for(x=1;x<10;x++);"
          testRT "for(var x;;);"
          testRT "for(var x=1;;);"
          testRT "for(var x;y;z){}"
          testRT "for(x in 5){}"
          testRT "for(var x in 5){}"
          testRT "for(let x;y;z){}"
          testRT "for(let x in 5){}"
          testRT "for(let x of 5){}"
          testRT "for(const x;y;z){}"
          testRT "for(const x in 5){}"
          testRT "for(const x of 5){}"
          testRT "for(x of 5){}"
          testRT "for(var x of 5){}"
          testRT "var x=1;"
          testRT "const x=1,y=2;"
          testRT "continue;"
          testRT "continue x;"
          testRT "break;"
          testRT "break x;"
          testRT "return;"
          testRT "return x;"
          testRT "with (x) {};"
          testRT "abc:x=1"
          testRT "switch (x) {}"
          testRT "switch (x) {case 1:break;}"
          testRT "switch (x) {case 0:\ncase 1:break;}"
          testRT "switch (x) {default:break;}"
          testRT "switch (x) {default:\ncase 1:break;}"
          testRT "var x=1;let y=2;"
          testRT "var [x, y]=z;"
          testRT "let {x: [y]}=z;"
          testRT "let yield=1"
  
      it "module" $ do
          testRTModule "import  def  from 'mod'"
          testRTModule "import  def  from   \"mod\";"
          testRTModule "import   * as foo  from   \"mod\"  ; "
          testRTModule "import  def, * as foo  from   \"mod\"  ; "
          testRTModule "import  { baz,  bar as   foo }  from   \"mod\"  ; "
          testRTModule "import  def, { baz,  bar as   foo }  from   \"mod\"  ; "
  
          testRTModule "export   {};"
          testRTModule "  export {}   ;  "
          testRTModule "export {  a  ,  b  ,  c  };"
          testRTModule "export {  a, X   as B,   c }"
          testRTModule "export   {}  from \"mod\";"
          testRTModule "export const a = 1 ; "
          testRTModule "export function f () {  } ; "
          testRTModule "export function * f () {  } ; "
          testRTModule "export   class Foo\nextends Bar\n{ get a () { return 1 ; }  static b ( x,y ) {} ; }   ; "
  
  
  testRT :: String -> Expectation
  testRT = testRTWith readJs
  
  testRTModule :: String -> Expectation
  testRTModule = testRTWith readJsModule
  
  testRTWith :: (String -> AST.JSAST) -> String -> Expectation
  testRTWith f str = renderToString (f str) `shouldBe` str
  