<commit_before>discard """
  output: '''{"foo":{"test":"123"}}'''
"""

import json, options

type
  Foo = ref object
    test: string
  Test = object
    foo: Option[Foo]

let js = """{"foo": {"test": "123"}}"""
let parsed = parseJson(js)
let a = parsed.to(Test)
echo $(%*a)


# RefPerson is used to test that overloaded `==` operator is not called by
# options. It is defined here in the global scope, because otherwise the test
# will not even consider the `==` operator. Different bug?
type RefPerson = ref object
  name: string

proc `==`(a, b: RefPerson): bool =
  assert(not a.isNil and not b.isNil)
  a.name == b.name

block options:
  # work around a bug in unittest
  let intNone = none(int)
  let stringNone = none(string)

  block example:
    proc find(haystack: string, needle: char): Option[int] =
      for i, c in haystack:
        if c == needle:
          return some i

    doAssert("abc".find('c').get() == 2)

    let result = "team".find('i')

    doAssert result == intNone
    doAssert result.isNone

  block some:
    doAssert some(6).get() == 6
    doAssert some("a").unsafeGet() == "a"
    doAssert some(6).isSome
    doAssert some("a").isSome

  block none:
    doAssertRaises UnpackDefect:
      discard none(int).get()
    doAssert(none(int).isNone)
    doAssert(not none(string).isSome)

  block equality:
    doAssert some("a") == some("a")
    doAssert some(7) != some(6)
    doAssert some("a") != stringNone
    doAssert intNone == intNone

    when compiles(some("a") == some(5)):
      doAssert false
    when compiles(none(string) == none(int)):
      doAssert false

  block get_with_a_default_value:
    doAssert(some("Correct").get("Wrong") == "Correct")
    doAssert(stringNone.get("Correct") == "Correct")

  block stringify:
    doAssert($(some("Correct")) == "Some(\"Correct\")")
    doAssert($(stringNone) == "None[string]")

  block map_with_a_void_result:
    var procRan = 0
    some(123).map(proc (v: int) = procRan = v)
    doAssert procRan == 123
    intNone.map(proc (v: int) = doAssert false)

  block map:
    doAssert(some(123).map(proc (v: int): int = v * 2) == some(246))
    doAssert(intNone.map(proc (v: int): int = v * 2).isNone)

  block filter:
    doAssert(some(123).filter(proc (v: int): bool = v == 123) == some(123))
    doAssert(some(456).filter(proc (v: int): bool = v == 123).isNone)
    doAssert(intNone.filter(proc (v: int): bool = doAssert false).isNone)

  block flatMap:
    proc addOneIfNotZero(v: int): Option[int] =
      if v != 0:
        result = some(v + 1)
      else:
        result = none(int)

    doAssert(some(1).flatMap(addOneIfNotZero) == some(2))
    doAssert(some(0).flatMap(addOneIfNotZero) == none(int))
    doAssert(some(1).flatMap(addOneIfNotZero).flatMap(addOneIfNotZero) == some(3))

    proc maybeToString(v: int): Option[string] =
      if v != 0:
        result = some($v)
      else:
        result = none(string)

    doAssert(some(1).flatMap(maybeToString) == some("1"))

    proc maybeExclaim(v: string): Option[string] =
      if v != "":
        result = some v & "!"
      else:
        result = none(string)

    doAssert(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!"))
    doAssert(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string))

  block SomePointer:
    var intref: ref int
    doAssert(option(intref).isNone)
    intref.new
    doAssert(option(intref).isSome)

    let tmp = option(intref)
    doAssert(sizeof(tmp) == sizeof(ptr int))

    var prc = proc (x: int): int = x + 1
    doAssert(option(prc).isSome)
    prc = nil
    doAssert(option(prc).isNone)

  block:
    doAssert(none[int]().isNone)
    doAssert(none(int) == none[int]())

  # "$ on typed with .name"
  block:
    type Named = object
      name: string

    let nobody = none(Named)
    doAssert($nobody == "None[Named]")

  # "$ on type with name()"
  block:
    type Person = object
      myname: string

    let noperson = none(Person)
    doAssert($noperson == "None[Person]")

  # "Ref type with overloaded `==`"
  block:
    let p = some(RefPerson.new())
    doAssert p.isSome<commit_msg>refactor the tests of options (#16527)<commit_after>discard """
  targets: "c js"
"""

import std/[json, options]


# RefPerson is used to test that overloaded `==` operator is not called by
# options. It is defined here in the global scope, because otherwise the test
# will not even consider the `==` operator. Different bug?
type RefPerson = ref object
  name: string

proc `==`(a, b: RefPerson): bool =
  assert(not a.isNil and not b.isNil)
  a.name == b.name


template disableJsVm(body) =
  # something doesn't work in JS VM
  when defined(js):
    when nimvm: discard
    else: body
  else:
    body

proc main() =
  type
    Foo = ref object
      test: string
    Test = object
      foo: Option[Foo]

  let js = """{"foo": {"test": "123"}}"""
  let parsed = parseJson(js)
  let a = parsed.to(Test)
  doAssert $(%*a) == """{"foo":{"test":"123"}}"""

  block options:
    # work around a bug in unittest
    let intNone = none(int)
    let stringNone = none(string)

    block example:
      proc find(haystack: string, needle: char): Option[int] =
        for i, c in haystack:
          if c == needle:
            return some i

      doAssert("abc".find('c').get() == 2)

      let result = "team".find('i')

      doAssert result == intNone
      doAssert result.isNone

    block some:
      doAssert some(6).get() == 6
      doAssert some("a").unsafeGet() == "a"
      doAssert some(6).isSome
      doAssert some("a").isSome

    block none:
      doAssertRaises UnpackDefect:
        discard none(int).get()
      doAssert(none(int).isNone)
      doAssert(not none(string).isSome)

    block equality:
      doAssert some("a") == some("a")
      doAssert some(7) != some(6)
      doAssert some("a") != stringNone
      doAssert intNone == intNone

      when compiles(some("a") == some(5)):
        doAssert false
      when compiles(none(string) == none(int)):
        doAssert false

    block get_with_a_default_value:
      doAssert(some("Correct").get("Wrong") == "Correct")
      doAssert(stringNone.get("Correct") == "Correct")

    block stringify:
      doAssert($(some("Correct")) == "Some(\"Correct\")")
      doAssert($(stringNone) == "None[string]")

    disableJsVm:
      block map_with_a_void_result:
        var procRan = 0
        # TODO closure anonymous functions doesn't work in VM with JS
        # Error: cannot evaluate at compile time: procRan
        some(123).map(proc (v: int) = procRan = v)
        doAssert procRan == 123
        intNone.map(proc (v: int) = doAssert false)

    block map:
      doAssert(some(123).map(proc (v: int): int = v * 2) == some(246))
      doAssert(intNone.map(proc (v: int): int = v * 2).isNone)

    block filter:
      doAssert(some(123).filter(proc (v: int): bool = v == 123) == some(123))
      doAssert(some(456).filter(proc (v: int): bool = v == 123).isNone)
      doAssert(intNone.filter(proc (v: int): bool = doAssert false).isNone)

    block flatMap:
      proc addOneIfNotZero(v: int): Option[int] =
        if v != 0:
          result = some(v + 1)
        else:
          result = none(int)

      doAssert(some(1).flatMap(addOneIfNotZero) == some(2))
      doAssert(some(0).flatMap(addOneIfNotZero) == none(int))
      doAssert(some(1).flatMap(addOneIfNotZero).flatMap(addOneIfNotZero) == some(3))

      proc maybeToString(v: int): Option[string] =
        if v != 0:
          result = some($v)
        else:
          result = none(string)

      doAssert(some(1).flatMap(maybeToString) == some("1"))

      proc maybeExclaim(v: string): Option[string] =
        if v != "":
          result = some v & "!"
        else:
          result = none(string)

      doAssert(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!"))
      doAssert(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string))

    block SomePointer:
      var intref: ref int
      doAssert(option(intref).isNone)
      intref.new
      doAssert(option(intref).isSome)

      let tmp = option(intref)
      doAssert(sizeof(tmp) == sizeof(ptr int))

      var prc = proc (x: int): int = x + 1
      doAssert(option(prc).isSome)
      prc = nil
      doAssert(option(prc).isNone)

    block:
      doAssert(none[int]().isNone)
      doAssert(none(int) == none[int]())

    # "$ on typed with .name"
    block:
      type Named = object
        name: string

      let nobody = none(Named)
      doAssert($nobody == "None[Named]")

    # "$ on type with name()"
    block:
      type Person = object
        myname: string

      let noperson = none(Person)
      doAssert($noperson == "None[Person]")

    # "Ref type with overloaded `==`"
    block:
      let p = some(RefPerson.new())
      doAssert p.isSome

    block: # test cstring
      block:
        let x = some("".cstring)
        doAssert x.isSome
        doAssert x.get == ""

      block:
        let x = some("12345".cstring)
        doAssert x.isSome
        doAssert x.get == "12345"

      block:
        let x = "12345".cstring
        let y = some(x)
        doAssert y.isSome
        doAssert y.get == "12345"

      block:
        let x = none(cstring)
        doAssert x.isNone
        doAssert $x == "None[cstring]"


static: main()
main()
{'fraction_non_alphanumeric': 0.1482873402770321, 'fraction_numerical': 0.014925373134328358, 'mean_word_length': 2.7662757784067935, 'pattern_counts': {'":': 10, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7557293', 'n_tokens_mistral': 3269, 'n_tokens_neox': 3081, 'n_words': 800}