context('format')

test_that('literal strings are unchanged', {
    expect_equal(fmt('this is a test'), 'this is a test')
    expect_equal(fmt('this', 'is', 'a', 'test'), 'thisisatest')
    expect_equal(fmt(c('this', 'is'), 'a', 'test'), 'thisisatest')
})

test_that('escaping works', {
    expect_equal(fmt('a {{test}}'), 'a {test}')
    expect_equal(fmt('a {{{{test}}'), 'a {{test}')
})

test_that('interpolation works', {
    expect_equal(fmt('a {"test"}'), 'a test')
    expect_equal(fmt('a {{{"test"}}}'), 'a {test}')
    x = 'test'
    expect_equal(fmt('a {x}'), 'a test')
    expect_equal(fmt('a {x}', x = 42L), 'a 42')
})

# test_that('escaping works inside interpolation', {
#     expect_equal(fmt('{"{{test"}'), '{test')
#     expect_equal(fmt('{"test}}"}'), 'test}')
# })

test_that('format modifiers work', {
    expect_equal(fmt('a {"test";"}'), sprintf('a %s', dQuote('test')))
    expect_equal(fmt("a {'test';'}"), sprintf('a %s', sQuote('test')))
    expect_equal(fmt('pi = {pi;.2f}'), sprintf('pi = %.2f', pi))
    x = 1 : 3
    expect_equal(fmt('x = {x}'), 'x = 1, 2, 3')
    expect_equal(fmt('{x;"}'), toString(dQuote(x)))
})

test_that('invalid formats raise an error', {
    expect_box_error(
        fmt('{12;1?}'),
        sprintf('unrecognized format modifier %s', dQuote('1\\?'))
    )
})

test_that('deparsed expression forms a single string', {
    expr = quote(long_call(with + some, 'arguments in it', that_total, over, 60L - ...chars))
    actual = fmt('{expr;"}')

    expect_equal(actual, dQuote(deparse1(expr)))
})

test_that('real use-cases from this package implementation work', {
    old_opts = options(useFancyQuotes = FALSE)
    on.exit(options(old_opts))

    # errors.r

    call = call('foo', 'bar', x = 1L)
    error = simpleError('test', call)
    expect_equal(
        fmt(
            '{msg}\n(inside {calls})',
            msg = conditionMessage(error),
            calls = paste(dQuote(deparse(conditionCall(error))), collapse = '\n')
        ),
        'test\n(inside "foo("bar", x = 1L)")'
    )

    fmt = '?'
    expect_equal(
        fmt('unrecognized format modifier {fmt;"}'),
        'unrecognized format modifier "?"'
    )

    # export.r

    expect_equal(
        fmt('{"export";"} can only be called from inside a module'),
        '"export" can only be called from inside a module'
    )

    name = quote(test)
    expect_equal(
        fmt(
            '{"export()";"} requires a list of unquoted names; ',
            '{name;"} is not a name'
        ),
        '"export()" requires a list of unquoted names; "test" is not a name',
    )

    expect_equal(
        fmt(
            'Invalid attempt to export names from an incompletely ',
            'loaded, cyclic import (module {name;"}) in line {line}.',
            name = 'foo/test',
            line = 42L
        ),
        'Invalid attempt to export names from an incompletely loaded, cyclic import (module "foo/test") in line 42.'
    )

    expect_equal(
        fmt(
            'The {"@export";"} tag may only be applied to assignments or ',
            '{"use";"} declarations.\n',
            'Used incorrectly in line {location}:\n',
            '    {paste(code, collapse = \'\n    \')}',
            code = c('foo', 'bar'),
            location = 42L
        ),
        'The "@export" tag may only be applied to assignments or "use" declarations.\nUsed incorrectly in line 42:\n    foo\n    bar'
    )

    # help.r

    topic = quote(foo$bar)
    expect_equal(
        fmt('{topic;"} is not a valid module help topic'),
        '"foo$bar" is not a valid module help topic'
    )

    expect_equal(
        fmt('Displaying documentation requires {"roxygen2";\'} installed'),
        'Displaying documentation requires \'roxygen2\' installed'
    )

    mod_name = 'foo'
    expect_equal(
        fmt('No documentation available for {mod_name;"}'),
        'No documentation available for "foo"'
    )

    subject = 'bar'
    expect_equal(
        fmt('No documentation available for {subject;"} in module {mod_name;"}'),
        'No documentation available for "bar" in module "foo"'
    )

    # info.r

    mod_name = 'foo/bar'
    base_paths = c('foo', 'bar', 'baz')
    expect_equal(
        fmt(
            'Unable to load module {mod_name;"}; ',
            'not found in {base_paths;"}'
        ),
        'Unable to load module "foo/bar"; not found in "foo", "bar", "baz"',
    )

    # use.r

    missing = 'foo'
    expect_equal(
        fmt(
            'Name{s} {missing;"} not exported by {mod_name;"}',
            s = if (length(missing) > 1L) 's' else ''
        ),
        'Name "foo" not exported by "foo/bar"',
    )

    missing = c('foo', 'bar')
    expect_equal(
        fmt(
            'Name{s} {missing;"} not exported by {mod_name;"}',
            s = if (length(missing) > 1L) 's' else ''
        ),
        'Names "foo", "bar" not exported by "foo/bar"'
    )
})
