├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── pull_request_template.md ├── renovate.json └── workflows │ ├── ci.yml │ └── lint.yml ├── .gitignore ├── .markdownlint.yml ├── .yamllint.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── SECURITY.md ├── benchmark └── euneus_benchmarker.erl ├── elvis.config ├── rebar.config ├── rebar.lock ├── src ├── euneus.app.src ├── euneus.erl ├── euneus_decoder.erl ├── euneus_encoder.erl └── euneus_formatter.erl └── test ├── euneus_SUITE.erl ├── euneus_benchmarker_SUITE.erl ├── euneus_benchmarker_SUITE_data ├── blockchain.json ├── giphy.json ├── github.json ├── govtrack.json ├── issue-90.json ├── json-generator-pretty.json ├── json-generator.json ├── pokedex.json ├── utf-8-escaped.json └── utf-8-unescaped.json ├── euneus_decoder_SUITE.erl ├── euneus_decoder_SUITE_data ├── i_number_double_huge_neg_exp.json ├── i_number_huge_exp.json ├── i_number_neg_int_huge_exp.json ├── i_number_pos_double_huge_exp.json ├── i_number_real_neg_overflow.json ├── i_number_real_pos_overflow.json ├── i_number_real_underflow.json ├── i_number_too_big_neg_int.json ├── i_number_too_big_pos_int.json ├── i_number_very_big_negative_int.json ├── i_object_key_lone_2nd_surrogate.json ├── i_string_1st_surrogate_but_2nd_missing.json ├── i_string_1st_valid_surrogate_2nd_invalid.json ├── i_string_UTF-16LE_with_BOM.json ├── i_string_UTF-8_invalid_sequence.json ├── i_string_UTF8_surrogate_U+D800.json ├── i_string_incomplete_surrogate_and_escape_valid.json ├── i_string_incomplete_surrogate_pair.json ├── i_string_incomplete_surrogates_escape_valid.json ├── i_string_invalid_lonely_surrogate.json ├── i_string_invalid_surrogate.json ├── i_string_invalid_utf-8.json ├── i_string_inverted_surrogates_U+1D11E.json ├── i_string_iso_latin_1.json ├── i_string_lone_second_surrogate.json ├── i_string_lone_utf8_continuation_byte.json ├── i_string_not_in_unicode_range.json ├── i_string_overlong_sequence_2_bytes.json ├── i_string_overlong_sequence_6_bytes.json ├── i_string_overlong_sequence_6_bytes_null.json ├── i_string_truncated-utf-8.json ├── i_string_utf16BE_no_BOM.json ├── i_string_utf16LE_no_BOM.json ├── i_structure_500_nested_arrays.json ├── i_structure_UTF-8_BOM_empty_object.json ├── n_array_1_true_without_comma.json ├── n_array_a_invalid_utf8.json ├── n_array_colon_instead_of_comma.json ├── n_array_comma_after_close.json ├── n_array_comma_and_number.json ├── n_array_double_comma.json ├── n_array_double_extra_comma.json ├── n_array_extra_close.json ├── n_array_extra_comma.json ├── n_array_incomplete.json ├── n_array_incomplete_invalid_value.json ├── n_array_inner_array_no_comma.json ├── n_array_invalid_utf8.json ├── n_array_items_separated_by_semicolon.json ├── n_array_just_comma.json ├── n_array_just_minus.json ├── n_array_missing_value.json ├── n_array_newlines_unclosed.json ├── n_array_number_and_comma.json ├── n_array_number_and_several_commas.json ├── n_array_spaces_vertical_tab_formfeed.json ├── n_array_star_inside.json ├── n_array_unclosed.json ├── n_array_unclosed_trailing_comma.json ├── n_array_unclosed_with_new_lines.json ├── n_array_unclosed_with_object_inside.json ├── n_incomplete_false.json ├── n_incomplete_null.json ├── n_incomplete_true.json ├── n_multidigit_number_then_00.json ├── n_number_++.json ├── n_number_+1.json ├── n_number_+Inf.json ├── n_number_-01.json ├── n_number_-1.0..json ├── n_number_-2..json ├── n_number_-NaN.json ├── n_number_.-1.json ├── n_number_.2e-3.json ├── n_number_0.1.2.json ├── n_number_0.3e+.json ├── n_number_0.3e.json ├── n_number_0.e1.json ├── n_number_0_capital_E+.json ├── n_number_0_capital_E.json ├── n_number_0e+.json ├── n_number_0e.json ├── n_number_1.0e+.json ├── n_number_1.0e-.json ├── n_number_1.0e.json ├── n_number_1_000.json ├── n_number_1eE2.json ├── n_number_2.e+3.json ├── n_number_2.e-3.json ├── n_number_2.e3.json ├── n_number_9.e+.json ├── n_number_Inf.json ├── n_number_NaN.json ├── n_number_U+FF11_fullwidth_digit_one.json ├── n_number_expression.json ├── n_number_hex_1_digit.json ├── n_number_hex_2_digits.json ├── n_number_infinity.json ├── n_number_invalid+-.json ├── n_number_invalid-negative-real.json ├── n_number_invalid-utf-8-in-bigger-int.json ├── n_number_invalid-utf-8-in-exponent.json ├── n_number_invalid-utf-8-in-int.json ├── n_number_minus_infinity.json ├── n_number_minus_sign_with_trailing_garbage.json ├── n_number_minus_space_1.json ├── n_number_neg_int_starting_with_zero.json ├── n_number_neg_real_without_int_part.json ├── n_number_neg_with_garbage_at_end.json ├── n_number_real_garbage_after_e.json ├── n_number_real_with_invalid_utf8_after_e.json ├── n_number_real_without_fractional_part.json ├── n_number_starting_with_dot.json ├── n_number_with_alpha.json ├── n_number_with_alpha_char.json ├── n_number_with_leading_zero.json ├── n_object_bad_value.json ├── n_object_bracket_key.json ├── n_object_comma_instead_of_colon.json ├── n_object_double_colon.json ├── n_object_emoji.json ├── n_object_garbage_at_end.json ├── n_object_key_with_single_quotes.json ├── n_object_lone_continuation_byte_in_key_and_trailing_comma.json ├── n_object_missing_colon.json ├── n_object_missing_key.json ├── n_object_missing_semicolon.json ├── n_object_missing_value.json ├── n_object_no-colon.json ├── n_object_non_string_key.json ├── n_object_non_string_key_but_huge_number_instead.json ├── n_object_repeated_null_null.json ├── n_object_several_trailing_commas.json ├── n_object_single_quote.json ├── n_object_trailing_comma.json ├── n_object_trailing_comment.json ├── n_object_trailing_comment_open.json ├── n_object_trailing_comment_slash_open.json ├── n_object_trailing_comment_slash_open_incomplete.json ├── n_object_two_commas_in_a_row.json ├── n_object_unquoted_key.json ├── n_object_unterminated-value.json ├── n_object_with_single_string.json ├── n_object_with_trailing_garbage.json ├── n_single_space.json ├── n_string_1_surrogate_then_escape.json ├── n_string_1_surrogate_then_escape_u.json ├── n_string_1_surrogate_then_escape_u1.json ├── n_string_1_surrogate_then_escape_u1x.json ├── n_string_accentuated_char_no_quotes.json ├── n_string_backslash_00.json ├── n_string_escape_x.json ├── n_string_escaped_backslash_bad.json ├── n_string_escaped_ctrl_char_tab.json ├── n_string_escaped_emoji.json ├── n_string_incomplete_escape.json ├── n_string_incomplete_escaped_character.json ├── n_string_incomplete_surrogate.json ├── n_string_incomplete_surrogate_escape_invalid.json ├── n_string_invalid-utf-8-in-escape.json ├── n_string_invalid_backslash_esc.json ├── n_string_invalid_unicode_escape.json ├── n_string_invalid_utf8_after_escape.json ├── n_string_leading_uescaped_thinspace.json ├── n_string_no_quotes_with_bad_escape.json ├── n_string_single_doublequote.json ├── n_string_single_quote.json ├── n_string_single_string_no_double_quotes.json ├── n_string_start_escape_unclosed.json ├── n_string_unescaped_ctrl_char.json ├── n_string_unescaped_newline.json ├── n_string_unescaped_tab.json ├── n_string_unicode_CapitalU.json ├── n_string_with_trailing_garbage.json ├── n_structure_100000_opening_arrays.json ├── n_structure_U+2060_word_joined.json ├── n_structure_UTF8_BOM_no_data.json ├── n_structure_angle_bracket_..json ├── n_structure_angle_bracket_null.json ├── n_structure_array_trailing_garbage.json ├── n_structure_array_with_extra_array_close.json ├── n_structure_array_with_unclosed_string.json ├── n_structure_ascii-unicode-identifier.json ├── n_structure_capitalized_True.json ├── n_structure_close_unopened_array.json ├── n_structure_comma_instead_of_closing_brace.json ├── n_structure_double_array.json ├── n_structure_end_array.json ├── n_structure_incomplete_UTF8_BOM.json ├── n_structure_lone-invalid-utf-8.json ├── n_structure_lone-open-bracket.json ├── n_structure_no_data.json ├── n_structure_null-byte-outside-string.json ├── n_structure_number_with_trailing_garbage.json ├── n_structure_object_followed_by_closing_object.json ├── n_structure_object_unclosed_no_value.json ├── n_structure_object_with_comment.json ├── n_structure_object_with_trailing_garbage.json ├── n_structure_open_array_apostrophe.json ├── n_structure_open_array_comma.json ├── n_structure_open_array_object.json ├── n_structure_open_array_open_object.json ├── n_structure_open_array_open_string.json ├── n_structure_open_array_string.json ├── n_structure_open_object.json ├── n_structure_open_object_close_array.json ├── n_structure_open_object_comma.json ├── n_structure_open_object_open_array.json ├── n_structure_open_object_open_string.json ├── n_structure_open_object_string_with_apostrophes.json ├── n_structure_open_open.json ├── n_structure_single_eacute.json ├── n_structure_single_star.json ├── n_structure_trailing_#.json ├── n_structure_uescaped_LF_before_string.json ├── n_structure_unclosed_array.json ├── n_structure_unclosed_array_partial_null.json ├── n_structure_unclosed_array_unfinished_false.json ├── n_structure_unclosed_array_unfinished_true.json ├── n_structure_unclosed_object.json ├── n_structure_unicode-identifier.json ├── n_structure_whitespace_U+2060_word_joiner.json ├── n_structure_whitespace_formfeed.json ├── y_array_arraysWithSpaces.json ├── y_array_empty-string.json ├── y_array_empty.json ├── y_array_ending_with_newline.json ├── y_array_false.json ├── y_array_heterogeneous.json ├── y_array_null.json ├── y_array_with_1_and_newline.json ├── y_array_with_leading_space.json ├── y_array_with_several_null.json ├── y_array_with_trailing_space.json ├── y_number.json ├── y_number_0e+1.json ├── y_number_0e1.json ├── y_number_after_space.json ├── y_number_double_close_to_zero.json ├── y_number_int_with_exp.json ├── y_number_minus_zero.json ├── y_number_negative_int.json ├── y_number_negative_one.json ├── y_number_negative_zero.json ├── y_number_real_capital_e.json ├── y_number_real_capital_e_neg_exp.json ├── y_number_real_capital_e_pos_exp.json ├── y_number_real_exponent.json ├── y_number_real_fraction_exponent.json ├── y_number_real_neg_exp.json ├── y_number_real_pos_exponent.json ├── y_number_simple_int.json ├── y_number_simple_real.json ├── y_object.json ├── y_object_basic.json ├── y_object_duplicated_key.json ├── y_object_duplicated_key_and_value.json ├── y_object_empty.json ├── y_object_empty_key.json ├── y_object_escaped_null_in_key.json ├── y_object_extreme_numbers.json ├── y_object_long_strings.json ├── y_object_simple.json ├── y_object_string_unicode.json ├── y_object_with_newlines.json ├── y_string_1_2_3_bytes_UTF-8_sequences.json ├── y_string_accepted_surrogate_pair.json ├── y_string_accepted_surrogate_pairs.json ├── y_string_allowed_escapes.json ├── y_string_backslash_and_u_escaped_zero.json ├── y_string_backslash_doublequotes.json ├── y_string_comments.json ├── y_string_double_escape_a.json ├── y_string_double_escape_n.json ├── y_string_escaped_control_character.json ├── y_string_escaped_noncharacter.json ├── y_string_in_array.json ├── y_string_in_array_with_leading_space.json ├── y_string_last_surrogates_1_and_2.json ├── y_string_nbsp_uescaped.json ├── y_string_nonCharacterInUTF-8_U+10FFFF.json ├── y_string_nonCharacterInUTF-8_U+FFFF.json ├── y_string_null_escape.json ├── y_string_one-byte-utf-8.json ├── y_string_pi.json ├── y_string_reservedCharacterInUTF-8_U+1BFFF.json ├── y_string_simple_ascii.json ├── y_string_space.json ├── y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json ├── y_string_three-byte-utf-8.json ├── y_string_two-byte-utf-8.json ├── y_string_u+2028_line_sep.json ├── y_string_u+2029_par_sep.json ├── y_string_uEscape.json ├── y_string_uescaped_newline.json ├── y_string_unescaped_char_delete.json ├── y_string_unicode.json ├── y_string_unicodeEscapedBackslash.json ├── y_string_unicode_2.json ├── y_string_unicode_U+10FFFE_nonchar.json ├── y_string_unicode_U+1FFFE_nonchar.json ├── y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json ├── y_string_unicode_U+2064_invisible_plus.json ├── y_string_unicode_U+FDD0_nonchar.json ├── y_string_unicode_U+FFFE_nonchar.json ├── y_string_unicode_escaped_double_quote.json ├── y_string_utf8.json ├── y_string_with_del_character.json ├── y_structure_lonely_false.json ├── y_structure_lonely_int.json ├── y_structure_lonely_negative_real.json ├── y_structure_lonely_null.json ├── y_structure_lonely_string.json ├── y_structure_lonely_true.json ├── y_structure_string_empty.json ├── y_structure_trailing_newline.json ├── y_structure_true_in_array.json └── y_structure_whitespace_array.json ├── euneus_encoder_SUITE.erl ├── euneus_encoder_SUITE_data ├── number_-9223372036854775808.json ├── number_-9223372036854775809.json ├── number_1.0.json ├── number_1.000000000000000005.json ├── number_1000000000000000.json ├── number_10000000000000000999.json ├── number_1e-999.json ├── number_1e6.json ├── number_9223372036854775807.json ├── number_9223372036854775808.json ├── object_key_nfc_nfd.json ├── object_key_nfd_nfc.json ├── object_same_key_different_values.json ├── object_same_key_same_value.json ├── object_same_key_unclear_values.json ├── string_1_escaped_invalid_codepoint.json ├── string_1_invalid_codepoint.json ├── string_2_escaped_invalid_codepoints.json ├── string_2_invalid_codepoints.json ├── string_3_escaped_invalid_codepoints.json ├── string_3_invalid_codepoints.json └── string_with_escaped_NULL.json └── euneus_formatter_SUITE.erl /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # These are supported funding model platforms 3 | 4 | github: [williamthome] 5 | patreon: # Replace with a single Patreon username 6 | open_collective: # Replace with a single Open Collective username 7 | ko_fi: # Replace with a single Ko-fi username 8 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 9 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 10 | liberapay: # Replace with a single Liberapay username 11 | issuehunt: # Replace with a single IssueHunt username 12 | otechie: # Replace with a single Otechie username 13 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 14 | custom: ['https://www.buymeacoffee.com/williamthome'] 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug to improve Euneus 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | #### The bug 11 | 12 | A clear and concise description of what the bug is. 13 | 14 | #### Software versions 15 | 16 | A list of software versions where the bug is apparent, as detailed as possible: 17 | 18 | * Erlang/OTP: ... 19 | * Euneus: ... 20 | * other (where applicable): ... 21 | 22 | #### How to replicate 23 | 24 | An ordered list of steps to replicate the bug: 25 | 26 | 1. run `rebar3 ci` 27 | 2. search for `...` in the error output 28 | 3. look at file `...` 29 | 30 | #### Expected behaviour 31 | 32 | What's expected to happen when you follow the steps listed above. 33 | 34 | #### Additional context 35 | 36 | Any other context about the bug. 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Request a feature for Euneus 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | #### Is your feature request related to a problem? 11 | 12 | A clear and concise description of what the problem is, e.g. "I'm always frustrated 13 | when ..." 14 | 15 | #### Describe the feature you'd like 16 | 17 | A clear and concise description of what you want to happen after the new feature 18 | is implemented. 19 | 20 | #### Describe alternatives you've considered 21 | 22 | A clear and concise description of any alternative solutions or features you've considered. 23 | 24 | #### Additional context 25 | 26 | Any other context about the feature request. 27 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | A brief description of your changes. 4 | 5 | Closes #<issue>. 6 | 7 | - [ ] I have performed a self-review of my changes 8 | - [ ] I have read and understood the [contributing guidelines](/williamthome/euneus/blob/main/CONTRIBUTING.md) 9 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended", 5 | "helpers:pinGitHubActionDigests", 6 | ":pinDevDependencies", 7 | ":pinDigestsDisabled" 8 | ], 9 | "packageRules": [ 10 | { 11 | "matchFileNames": [ 12 | ".github/**/*.yml" 13 | ], 14 | "groupName": "dev tools" 15 | }, 16 | { 17 | "matchFileNames": [ 18 | "rebar.config" 19 | ], 20 | "groupName": "rebar.config deps" 21 | }, 22 | { 23 | "matchPackagePrefixes": [ 24 | "minimum_otp_vsn" 25 | ], 26 | "enabled": false 27 | } 28 | ], 29 | "customManagers": [ 30 | { 31 | "description": "Match versions (per datasource and depName) in .github/**/*.yml", 32 | "customType": "regex", 33 | "fileMatch": [ 34 | ".github/.*/.*\\.yml" 35 | ], 36 | "matchStrings": [ 37 | "# renovate datasource: (?[^,]+), depName: (?[^\\n]+)\\n.+?(?v?\\d+(\\.\\d+(\\.\\d+)?)?(-[^\\n]+)?)\\n" 38 | ] 39 | }, 40 | { 41 | "description": "Match versions in rebar.config", 42 | "customType": "regex", 43 | "fileMatch": [ 44 | "rebar.config" 45 | ], 46 | "datasourceTemplate": "hex", 47 | "matchStrings": [ 48 | "{(?[^,]+), \"(?\\d+\\.\\d+(\\.\\d+)?)\"" 49 | ], 50 | "versioningTemplate": "semver" 51 | } 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: CI 3 | 4 | "on": 5 | push: 6 | branches: 7 | - main 8 | pull_request: 9 | branches: 10 | - "*" 11 | workflow_dispatch: {} 12 | merge_group: 13 | 14 | concurrency: 15 | group: ${{github.workflow}}-${{github.ref}} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | ci: 20 | name: CI OTP-${{matrix.otp-version}} 21 | 22 | runs-on: ${{matrix.os}} 23 | 24 | strategy: 25 | matrix: 26 | otp-version: [24, 25, 26, 27] 27 | os: [ubuntu-24.04] 28 | 29 | steps: 30 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 31 | 32 | - uses: erlef/setup-beam@8aa8a857c6be0daae6e97272bb299d5b942675a4 # v1.19.0 33 | id: setup-beam 34 | with: 35 | otp-version: ${{matrix.otp-version}} 36 | rebar3-version: 3.23.0 37 | 38 | - name: Restore _build 39 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 40 | with: 41 | path: _build 42 | key: "_build-cache-for\ 43 | -os-${{runner.os}}\ 44 | -otp-${{steps.setup-beam.outputs.otp-version}}\ 45 | -rebar3-${{steps.setup-beam.outputs.rebar3-version}}\ 46 | -hash-${{hashFiles('rebar.lock')}}-${{hashFiles('rebar.config')}}" 47 | 48 | - name: Restore rebar3's cache 49 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 50 | with: 51 | path: ~/.cache/rebar3 52 | key: "rebar3-cache-for\ 53 | -os-${{runner.os}}\ 54 | -otp-${{steps.setup-beam.outputs.otp-version}}\ 55 | -rebar3-${{steps.setup-beam.outputs.rebar3-version}}\ 56 | -hash-${{hashFiles('rebar.lock')}}" 57 | 58 | - name: Continuous Integration (Polyfill) 59 | if: ${{fromJSON(matrix.otp-version) < 27}} 60 | run: | 61 | rebar3 as test polyfill_ci 62 | 63 | - name: Continuous Integration 64 | if: ${{fromJSON(matrix.otp-version) >= 27}} 65 | run: | 66 | rebar3 as test ci 67 | 68 | - name: Check if build left artifacts 69 | run: | 70 | rebar3 unlock --all 71 | rebar3 upgrade --all 72 | git diff --exit-code 73 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Lint 3 | 4 | "on": 5 | push: 6 | branches: 7 | - main 8 | pull_request: 9 | branches: 10 | - "*" 11 | workflow_dispatch: {} 12 | merge_group: 13 | 14 | concurrency: 15 | group: ${{github.workflow}}-${{github.ref}} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | lint: 20 | name: Lint 21 | 22 | runs-on: ubuntu-24.04 23 | 24 | steps: 25 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 26 | 27 | # uses .markdownlint.yml for configuration 28 | - name: markdownlint 29 | uses: DavidAnson/markdownlint-cli2-action@05f32210e84442804257b2a6f20b273450ec8265 # v19.1.0 30 | with: 31 | globs: | 32 | .github/**/*.md 33 | *.md 34 | 35 | - name: yamllint 36 | uses: ibiqlik/action-yamllint@2576378a8e339169678f9939646ee3ee325e845c # v3.1.1 37 | with: 38 | file_or_dir: | 39 | .github/**/*.yml 40 | .*.yml 41 | strict: true 42 | config_file: .yamllint.yml 43 | 44 | - name: actionlint 45 | uses: reviewdog/action-actionlint@a5524e1c19e62881d79c1f1b9b6f09f16356e281 # v1.65.2 46 | env: 47 | SHELLCHECK_OPTS: -o all 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | _checkouts 3 | doc/ 4 | erl_crash.dump 5 | rebar3.crashdump 6 | -------------------------------------------------------------------------------- /.markdownlint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | default: true 3 | MD013: 4 | line_length: 100 5 | code_blocks: false 6 | -------------------------------------------------------------------------------- /.yamllint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | rules: 4 | line-length: 5 | max: 100 6 | comments: 7 | min-spaces-from-content: 1 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | See the [Releases](https://github.com/williamthome/euneus/releases) page. 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official email address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | [INSERT CONTACT METHOD]. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations 133 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Euneus 2 | 3 | 1. [License](#license) 4 | 1. [Reporting a bug](#reporting-a-bug) 5 | 1. [Requesting or implementing a feature](#requesting-or-implementing-a-feature) 6 | 1. [Submitting your changes](#submitting-your-changes) 7 | 1. [Code Style](#code-style) 8 | 1. [Committing your changes](#committing-your-changes) 9 | 1. [Pull requests and branching](#pull-requests-and-branching) 10 | 1. [Credits](#credits) 11 | 12 | ## License 13 | 14 | Euneus is licensed under the [Apache License Version 2.0](LICENSE.md), for all code. 15 | 16 | ## Reporting a bug 17 | 18 | Euneus is not perfect software and will be buggy. 19 | 20 | Bugs can be reported via 21 | [GitHub issues: bug report](https://github.com/williamthome/euneus/issues/new?template=bug_report.md). 22 | 23 | Some contributors and maintainers may be unpaid developers working on Euneus, in their own time, 24 | with limited resources. We ask for respect and understanding, and will provide the same back. 25 | 26 | If your contribution is an actual bug fix, we ask you to include tests that, not only show the issue 27 | is solved, but help prevent future regressions related to it. 28 | 29 | ## Requesting or implementing a feature 30 | 31 | Before requesting or implementing a new feature, do the following: 32 | 33 | - search, in existing [issues](https://github.com/williamthome/euneus/issues) (open or closed), 34 | whether the feature might already be in the works, or has already been rejected, 35 | - make sure you're using the latest software release (or even the latest code, if you're going for 36 | _bleeding edge_). 37 | 38 | If this is done, open up a 39 | [GitHub issues: feature request](https://github.com/williamthome/euneus/issues/new?template=feature_request.md). 40 | 41 | We may discuss details with you regarding the implementation, and its inclusion within the project. 42 | 43 | We try to have as many of Euneus's features tested as possible. Everything that a user can do, 44 | and is repeatable in any way, should be tested, to guarantee backwards compatible. 45 | 46 | ## Submitting your changes 47 | 48 | ### Code Style 49 | 50 | - do not introduce trailing whitespace 51 | - indentation is 4 spaces, not tabs 52 | - try not to introduce lines longer than 100 characters 53 | - write small functions whenever possible, and use descriptive names for functions and variables 54 | - comment tricky or non-obvious decisions made to explain their rationale 55 | 56 | ### Committing your changes 57 | 58 | Merging to the `main` branch will usually be preceded by a squash. 59 | 60 | While it's Ok (and expected) your commit messages relate to why a given change was made, be aware 61 | that the final commit (the merge one) will be the issue title, so it's important it is as specific 62 | as possible. This will also help eventual automated changelog generation. 63 | 64 | ### Pull requests and branching 65 | 66 | All fixes to Euneus end up requiring a +1 from one or more of the project's maintainers. 67 | 68 | During the review process, you may be asked to correct or edit a few things before a final rebase 69 | to merge things. Do send edits as individual commits to allow for gradual and partial reviews to be 70 | done by reviewers. 71 | 72 | ### Credits 73 | 74 | Euneus has been improved by 75 | [many contributors](https://github.com/williamthome/euneus/graphs/contributors)! 76 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Apache License 2 | 3 | Version 2.0, January 2004 4 | 5 | 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | ## 1. Definitions 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, and 12 | distribution as defined by Sections 1 through 9 of this document. 13 | 14 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 15 | owner that is granting the License. 16 | 17 | "Legal Entity" shall mean the union of the acting entity and all other entities 18 | that control, are controlled by, or are under common control with that entity. 19 | For the purposes of this definition, "control" means (i) the power, direct or 20 | indirect, to cause the direction or management of such entity, whether by 21 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity exercising 25 | permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, including 28 | but not limited to software source code, documentation source, and configuration 29 | files. 30 | 31 | "Object" form shall mean any form resulting from mechanical transformation or 32 | translation of a Source form, including but not limited to compiled object code, 33 | generated documentation, and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or Object form, made 36 | available under the License, as indicated by a copyright notice that is included 37 | in or attached to the work (an example is provided in the Appendix below). 38 | 39 | "Derivative Works" shall mean any work, whether in Source or Object form, that 40 | is based on (or derived from) the Work and for which the editorial revisions, 41 | annotations, elaborations, or other modifications represent, as a whole, an 42 | original work of authorship. For the purposes of this License, Derivative Works 43 | shall not include works that remain separable from, or merely link (or bind by 44 | name) to the interfaces of, the Work and Derivative Works thereof. 45 | 46 | "Contribution" shall mean any work of authorship, including the original version 47 | of the Work and any modifications or additions to that Work or Derivative Works 48 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 49 | by the copyright owner or by an individual or Legal Entity authorized to submit 50 | on behalf of the copyright owner. For the purposes of this definition, 51 | "submitted" means any form of electronic, verbal, or written communication sent 52 | to the Licensor or its representatives, including but not limited to 53 | communication on electronic mailing lists, source code control systems, and 54 | issue tracking systems that are managed by, or on behalf of, the Licensor for 55 | the purpose of discussing and improving the Work, but excluding communication 56 | that is conspicuously marked or otherwise designated in writing by the copyright 57 | owner as "Not a Contribution." 58 | 59 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 60 | of whom a Contribution has been received by Licensor and subsequently 61 | incorporated within the Work. 62 | 63 | ## 2. Grant of Copyright License 64 | 65 | Subject to the terms and conditions of this License, each Contributor hereby 66 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 67 | irrevocable copyright license to reproduce, prepare Derivative Works of, 68 | publicly display, publicly perform, sublicense, and distribute the Work and such 69 | Derivative Works in Source or Object form. 70 | 71 | ## 3. Grant of Patent License 72 | 73 | Subject to the terms and conditions of this License, each Contributor hereby 74 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 75 | irrevocable (except as stated in this section) patent license to make, have 76 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 77 | such license applies only to those patent claims licensable by such Contributor 78 | that are necessarily infringed by their Contribution(s) alone or by combination 79 | of their Contribution(s) with the Work to which such Contribution(s) was 80 | submitted. If You institute patent litigation against any entity (including a 81 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 82 | Contribution incorporated within the Work constitutes direct or contributory 83 | patent infringement, then any patent licenses granted to You under this License 84 | for that Work shall terminate as of the date such litigation is filed. 85 | 86 | ## 4. Redistribution 87 | 88 | You may reproduce and distribute copies of the Work or Derivative Works thereof 89 | in any medium, with or without modifications, and in Source or Object form, 90 | provided that You meet the following conditions: 91 | 92 | 1. You must give any other recipients of the Work or Derivative Works a copy of 93 | this License; and 94 | 95 | 2. You must cause any modified files to carry prominent notices stating that 96 | You changed the files; and 97 | 98 | 3. You must retain, in the Source form of any Derivative Works that You 99 | distribute, all copyright, patent, trademark, and attribution notices from 100 | the Source form of the Work, excluding those notices that do not pertain to 101 | any part of the Derivative Works; and 102 | 103 | 4. If the Work includes a "NOTICE" text file as part of its distribution, then 104 | any Derivative Works that You distribute must include a readable copy of the 105 | attribution notices contained within such NOTICE file, excluding those 106 | notices that do not pertain to any part of the Derivative Works, in at least 107 | one of the following places: within a NOTICE text file distributed as part 108 | of the Derivative Works; within the Source form or documentation, if 109 | provided along with the Derivative Works; or, within a display generated by 110 | the Derivative Works, if and wherever such third-party notices normally 111 | appear. The contents of the NOTICE file are for informational purposes only 112 | and do not modify the License. You may add Your own attribution notices 113 | within Derivative Works that You distribute, alongside or as an addendum to 114 | the NOTICE text from the Work, provided that such additional attribution 115 | notices cannot be construed as modifying the License. 116 | 117 | You may add Your own copyright statement to Your modifications and may provide 118 | additional or different license terms and conditions for use, reproduction, or 119 | distribution of Your modifications, or for any such Derivative Works as a whole, 120 | provided Your use, reproduction, and distribution of the Work otherwise complies 121 | with the conditions stated in this License. 122 | 123 | ## 5. Submission of Contributions 124 | 125 | Unless You explicitly state otherwise, any Contribution intentionally submitted 126 | for inclusion in the Work by You to the Licensor shall be under the terms and 127 | conditions of this License, without any additional terms or conditions. 128 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 129 | any separate license agreement you may have executed with Licensor regarding 130 | such Contributions. 131 | 132 | ## 6. Trademarks 133 | 134 | This License does not grant permission to use the trade names, trademarks, 135 | service marks, or product names of the Licensor, except as required for 136 | reasonable and customary use in describing the origin of the Work and 137 | reproducing the content of the NOTICE file. 138 | 139 | ## 7. Disclaimer of Warranty 140 | 141 | Unless required by applicable law or agreed to in writing, Licensor provides the 142 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 143 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 144 | including, without limitation, any warranties or conditions of TITLE, NON- 145 | INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 146 | solely responsible for determining the appropriateness of using or 147 | redistributing the Work and assume any risks associated with Your exercise of 148 | permissions under this License. 149 | 150 | ## 8. Limitation of Liability 151 | 152 | In no event and under no legal theory, whether in tort (including negligence), 153 | contract, or otherwise, unless required by applicable law (such as deliberate 154 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 155 | liable to You for damages, including any direct, indirect, special, incidental, 156 | or consequential damages of any character arising as a result of this License or 157 | out of the use or inability to use the Work (including but not limited to 158 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 159 | any and all other commercial damages or losses), even if such Contributor has 160 | been advised of the possibility of such damages. 161 | 162 | ## 9. Accepting Warranty or Additional Liability 163 | 164 | While redistributing the Work or Derivative Works thereof, You may choose to 165 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 166 | other liability obligations and/or rights consistent with this License. However, 167 | in accepting such obligations, You may act only on Your own behalf and on Your 168 | sole responsibility, not on behalf of any other Contributor, and only if You 169 | agree to indemnify, defend, and hold each Contributor harmless for any liability 170 | incurred by, or claims asserted against, such Contributor by reason of your 171 | accepting any such warranty or additional liability. 172 | 173 | END OF TERMS AND CONDITIONS 174 | 175 | Copyright 2024, William Fank Thomé . 176 | 177 | Licensed under the Apache License, Version 2.0 (the "License"); 178 | you may not use this file except in compliance with the License. 179 | You may obtain a copy of the License at 180 | 181 | 182 | 183 | Unless required by applicable law or agreed to in writing, software 184 | distributed under the License is distributed on an "AS IS" BASIS, 185 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 186 | See the License for the specific language governing permissions and 187 | limitations under the License. 188 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Euneus 2 | 3 | [![Github Actions](https://github.com/williamthome/euneus/workflows/CI/badge.svg)](https://github.com/williamthome/euneus/actions) 4 | [![Coverage](https://raw.githubusercontent.com/cicirello/jacoco-badge-generator/main/tests/100.svg)](https://github.com/williamthome/euneus/actions/workflows/ci.yml) 5 | [![Erlang Versions](https://img.shields.io/badge/Erlang%2FOTP-24%2B-green?style=flat-square)](http://www.erlang.org) 6 | [![Latest Release](https://img.shields.io/github/release/williamthome/euneus.svg?style=flat-square)](https://github.com/williamthome/euneus/releases/latest) 7 | [![Hex Version](https://img.shields.io/hexpm/v/euneus.svg)](https://hex.pm/packages/euneus) 8 | [![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/euneus/) 9 | [![Total Download](https://img.shields.io/hexpm/dt/euneus.svg)](https://hex.pm/packages/euneus) 10 | [![License](https://img.shields.io/hexpm/l/euneus.svg)](https://github.com/williamthome/euneus/blob/main/LICENSE) 11 | [![Last Updated](https://img.shields.io/github/last-commit/williamthome/euneus.svg)](https://github.com/williamthome/euneus/commits/main) 12 | 13 | An incredibly flexible and performant JSON parser, generator and formatter in pure Erlang. 14 | 15 | Euneus is built on the top of the new [OTP json module](https://erlang.org/documentation/doc-15.0-rc3/lib/stdlib-6.0/doc/html/json.html). 16 | 17 | Both encoder and decoder fully conform to [RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259) 18 | and [ECMA 404](https://ecma-international.org/publications-and-standards/standards/ecma-404/) standards 19 | and are tested using [JSONTestSuite](https://github.com/nst/JSONTestSuite). 20 | 21 | Detailed examples and further explanation can be found at [hexdocs](https://hexdocs.pm/euneus). 22 | 23 | ## Requirements 24 | 25 | OTP >= 24. 26 | 27 | ## Why should you use Euneus over the OTP json module? 28 | 29 | The new OTP `json` module is incredible and blazing fast! 30 | 31 | Unfortunately, it is only available for OTP >= 27. Euneus is available from OTP >= 24. 32 | 33 | Also, Euneus simplifies a lot of overheads with the new OTP `json` module without 34 | losing any option provided by the json module and keeping its performance. 35 | 36 | A simple example comparing the OTP `json` module with Euneus decoding object keys: 37 | 38 | ```erlang 39 | > json:decode(<<"{\"foo\":\"bar\"}">>, [], #{object_push => fun(K, V, Acc) -> [{binary_to_atom(K), V} | Acc] end}). 40 | {#{foo => <<"bar">>},[],<<>>} 41 | > euneus:decode(<<"{\"foo\":\"bar\"}">>, #{object_keys => atom}). 42 | #{foo => <<"bar">>} 43 | ``` 44 | 45 | ### Encode Features 46 | 47 | Some reasons to use Euneus for JSON encoding: 48 | 49 | - Possibility to skip values 50 | - Encoding proplists (proplists are not encoded by the OTP json module) 51 | - Sort object keys 52 | - Simple custom encoding via codecs: 53 | 54 | ```erlang 55 | -type codec() :: 56 | timestamp 57 | | datetime 58 | | ipv4 59 | | ipv6 60 | | {records, #{Name :: atom() := {Fields :: [atom()], Size :: pos_integer()}}} 61 | | codec_fun() 62 | | custom_codec(). 63 | ``` 64 | 65 | #### Encode Codecs 66 | 67 | ##### Encode timestamp 68 | 69 | ```erlang 70 | > euneus:encode({0, 0, 0}, #{codecs => [timestamp]}). 71 | <<"\"1970-01-01T00:00:00.000Z\"">> 72 | ``` 73 | 74 | ##### Encode datetime 75 | 76 | ```erlang 77 | > euneus:encode({{1970, 01, 01}, {00, 00, 00}}, #{codecs => [datetime]}). 78 | <<"\"1970-01-01T00:00:00Z\"">> 79 | ``` 80 | 81 | ##### Encode ipv4 82 | 83 | ```erlang 84 | > euneus:encode({0, 0, 0, 0}, #{codecs => [ipv4]}). 85 | <<"\"0.0.0.0\"">> 86 | ``` 87 | 88 | ##### Encode ipv6 89 | 90 | ```erlang 91 | > euneus:encode({16#fe80, 0, 0, 0, 16#204, 16#acff, 16#fe17, 16#bf38}, #{codecs => [ipv6]}). 92 | <<"\"fe80::204:acff:fe17:bf38\"">> 93 | ``` 94 | 95 | ##### Encode record 96 | 97 | ```erlang 98 | % -record(foo, {foo, bar}). 99 | > euneus:encode(#foo{foo = 1, bar = 2}, #{ 100 | codecs => [ 101 | {records, #{ 102 | foo => {record_info(fields, foo), record_info(size, foo)} 103 | }} 104 | ] 105 | }). 106 | <<"{\"foo\":1,\"bar\":2}">> 107 | ``` 108 | 109 | ### Decode Features 110 | 111 | Some reasons to use Euneus for JSON decoding: 112 | 113 | - Faster decoding than the OTP `json` module via some options: 114 | 115 | ```erlang 116 | #{ 117 | array_finish => reversed, 118 | object_finish => reversed_proplist % or proplist 119 | } 120 | ``` 121 | 122 | - The overhead of transforming binary keys to, e.g., atoms 123 | - Simple custom decoding via codecs: 124 | 125 | ```erlang 126 | -type codec() :: 127 | copy 128 | | timestamp 129 | | datetime 130 | | ipv4 131 | | ipv6 132 | | pid 133 | | port 134 | | reference 135 | | codec_callback(). 136 | ``` 137 | 138 | #### Decode Object keys 139 | 140 | ##### Keys to binary (default) 141 | 142 | ```erlang 143 | > euneus:decode(<<"{\"foo\":\"bar\"}">>). 144 | #{<<"foo">> => <<"bar">>} 145 | ``` 146 | 147 | ##### Keys copy 148 | 149 | Just do a binary copy of the key. 150 | 151 | ```erlang 152 | > euneus:decode(<<"{\"foo\":\"bar\"}">>, #{object_keys => copy}). 153 | #{<<"foo">> => <<"bar">>} 154 | ``` 155 | 156 | ##### Keys to atom 157 | 158 | ```erlang 159 | > euneus:decode(<<"{\"foo\":\"bar\"}">>, #{object_keys => atom}). 160 | #{foo => <<"bar">>} 161 | ``` 162 | 163 | ##### Keys to existing atom 164 | 165 | ```erlang 166 | > euneus:decode(<<"{\"foo\":\"bar\"}">>, #{object_keys => existing_atom}). 167 | #{foo => <<"bar">>} 168 | ``` 169 | 170 | #### Decode Codecs 171 | 172 | ##### Decode copy 173 | 174 | Just do a binary copy of the value. 175 | 176 | ```erlang 177 | > euneus:decode(<<"\"foo\"">>, #{codecs => [copy]}). 178 | <<"foo">> 179 | ``` 180 | 181 | ##### Decode timestamp 182 | 183 | ```erlang 184 | > euneus:decode(<<"\"1970-01-01T00:00:00.000Z\"">>, #{codecs => [timestamp]}). 185 | {0,0,0} 186 | ``` 187 | 188 | ##### Decode datetime 189 | 190 | ```erlang 191 | > euneus:decode(<<"\"1970-01-01T00:00:00Z\"">>, #{codecs => [datetime]}). 192 | {{1970,1,1},{0,0,0}} 193 | ``` 194 | 195 | ##### Decode ipv4 196 | 197 | ```erlang 198 | > euneus:decode(<<"\"0.0.0.0\"">>, #{codecs => [ipv4]}). 199 | {0,0,0,0} 200 | ``` 201 | 202 | ##### Decode ipv6 203 | 204 | ```erlang 205 | > euneus:decode(<<"\"::\"">>, #{codecs => [ipv6]}). 206 | {0,0,0,0,0,0,0,0} 207 | > euneus:decode(<<"\"::1\"">>, #{codecs => [ipv6]}). 208 | {0,0,0,0,0,0,0,1} 209 | > euneus:decode(<<"\"::192.168.42.2\"">>, #{codecs => [ipv6]}). 210 | {0,0,0,0,0,0,49320,10754} 211 | > euneus:decode(<<"\"fe80::204:acff:fe17:bf38\"">>, #{codecs => [ipv6]}). 212 | {65152,0,0,0,516,44287,65047,48952} 213 | ``` 214 | 215 | ##### Decode pid 216 | 217 | ```erlang 218 | > euneus:decode(<<"\"<0.92.0>\"">>, #{codecs => [pid]}). 219 | <0.92.0> 220 | ``` 221 | 222 | ##### Decode port 223 | 224 | ```erlang 225 | > euneus:decode(<<"\"#Port<0.1>\"">>, #{codecs => [port]}). 226 | #Port<0.1> 227 | ``` 228 | 229 | ##### Decode reference 230 | 231 | ```erlang 232 | > euneus:decode(<<"\"#Ref<0.314572725.1088159747.110918>\"">>, #{codecs => [reference]}). 233 | #Ref<0.314572725.1088159747.110918> 234 | ``` 235 | 236 | ## Installation 237 | 238 | ### Erlang 239 | 240 | ```erlang 241 | % rebar.config 242 | {deps, [ 243 | {json_polyfill, "~> 0.2"}, % Required only for OTP < 27 244 | {euneus, "~> 2.4"} 245 | ]}. 246 | ``` 247 | 248 | ### Elixir 249 | 250 | ```elixir 251 | # mix.exs 252 | defp deps do 253 | [ 254 | {:json_polyfill, "~> 0.2"}, # Required only for OTP < 27 255 | {:euneus, "~> 2.4"} 256 | ] 257 | end 258 | ``` 259 | 260 | ## Basic usage 261 | 262 | ```erlang 263 | 1> euneus:encode(#{age => 68, name => <<"Joe Armstrong">>, nationality => <<"British">>}). 264 | <<"{\"name\":\"Joe Armstrong\",\"age\":68,\"nationality\":\"British\"}">> 265 | 2> euneus:decode(v(1)). 266 | #{<<"age">> => 68,<<"name">> => <<"Joe Armstrong">>,<<"nationality">> => <<"British">>} 267 | ``` 268 | 269 | ## Encode 270 | 271 | The functions `euneus:encode/1` `euneus:encode/2` encodes an Erlang term into a binary JSON. 272 | The second argument of `euneus:encode/2` are options. 273 | 274 | Please see the `m:euneus_encoder` [documentation](https://hexdocs.pm/euneus/euneus_encoder.html) 275 | for more examples and detailed explanation. 276 | 277 | The data mapping and error reasons can be found in the OTP json encode function [documentation](https://erlang.org/documentation/doc-15.0-rc3/lib/stdlib-6.0/doc/html/json.html#encode/1). 278 | 279 | ## Decode 280 | 281 | The functions `euneus:decode/1` and `euneus:decode/2` decodes a binary JSON into an Erlang term. 282 | The second argument of `euneus:decode/2` are options. 283 | 284 | Please see the `m:euneus_decoder` [documentation](https://hexdocs.pm/euneus/euneus_decoder.html) 285 | for more examples and detailed explanation. 286 | 287 | The data mapping and error reasons can be found in the OTP json decode function [documentation](https://erlang.org/documentation/doc-15.0-rc3/lib/stdlib-6.0/doc/html/json.html#decode/1). 288 | 289 | ## Stream 290 | 291 | Three functions provide JSON decode streaming: 292 | 293 | - `euneus:decode_stream_start/1` - Equivalent to `euneus:decode_stream_start(JSON, #{})`; 294 | - `euneus:decode_stream_start/2` - Begin parsing a stream of bytes of a JSON value; 295 | - `euneus:decode_stream_continue/2` - Continue parsing a stream of bytes of a JSON value. 296 | 297 | Please see the `m:euneus_decoder` [documentation](https://hexdocs.pm/euneus/euneus_decoder.html) 298 | for more examples and detailed explanation. 299 | 300 | ## Format 301 | 302 | Two functions provide JSON formatting: 303 | 304 | - `euneus:minify/1` - Removes any extra spaces and new line characters; 305 | - `euneus:format/2` - Formats the JSON by passing custom options. 306 | 307 | Please see the `m:euneus_formatter` [documentation](https://hexdocs.pm/euneus/euneus_formatter.html) 308 | for more examples and detailed explanation. 309 | 310 | ## Benchmark 311 | 312 | The benchmarks are implemented very simply, but they are a good start foroptimizing 313 | Euneus since no optimizations have been made. You will find the benchmark commands 314 | in `euneus_benchmarker`, and data and tests under the test folder. 315 | 316 | > [!IMPORTANT] 317 | > For the first benchmark run, bootstrapping `erlperf` is required: 318 | > 319 | > ```console 320 | > $ rebar3 as benchmark shell 321 | > 322 | > 1> euneus_benchmarker:bootstrap(). 323 | > ===> Verifying dependencies... 324 | > ===> Analyzing applications... 325 | > ===> Compiling erlperf 326 | > ===> Building escript for erlperf... 327 | > ok 328 | > ``` 329 | 330 | ### Results 331 | 332 | > Setup: 333 | > 334 | > - OS : Linux 335 | > - CPU: 12th Gen Intel(R) Core(TM) i9-12900HX 336 | > - VM : Erlang/OTP 27 [erts-15.0.1] [source] [64-bit] [smp:24:24] [ds:24:24:10] [async-threads:1] [jit:ns] 337 | 338 | ```console 339 | $ rebar3 as benchmark shell 340 | 341 | 1> euneus_benchmarker:encode_benchmark(). 342 | Code || Samples Avg StdDev Median P99 Iteration Rel 343 | jiffy 1 3 26 36.69% 25 36 38474 us 100% 344 | euneus 1 3 20 38.20% 18 29 49197 us 78% 345 | thoas 1 3 10 36.06% 9 14 100 ms 38% 346 | 347 | 2> euneus_benchmarker:decode_benchmark(). 348 | Code || Samples Avg StdDev Median P99 Iteration Rel 349 | euneus 1 3 24 2.44% 24 24 42268 us 100% 350 | jiffy 1 3 19 3.09% 19 19 53589 us 79% 351 | thoas 1 3 14 0.00% 14 14 71452 us 59% 352 | ``` 353 | 354 | ## Sponsors 355 | 356 | If you like this tool, please consider [sponsoring me](https://github.com/sponsors/williamthome). 357 | I'm thankful for your never-ending support :heart: 358 | 359 | I also accept coffees :coffee: 360 | 361 | [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/williamthome) 362 | 363 | ## License 364 | 365 | Copyright (c) 2024 [William Fank Thomé](https://github.com/williamthome) 366 | 367 | Euneus is 100% open-source and community-driven. All components are 368 | available under the Apache 2 License on [GitHub](https://github.com/williamthome/euneus). 369 | 370 | See [LICENSE.md](LICENSE.md) for more information. 371 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security policy 2 | 3 | Thanks for helping make Euneus safer for everyone. 4 | 5 | Find below updated information on our security policy. 6 | 7 | ## Security 8 | 9 | We take the security of this software seriously. 10 | 11 | We don't implement a bug bounty program or bounty rewards, but will work with 12 | you to ensure that your findings get the appropriate handling. 13 | 14 | ## Reporting Security Issues 15 | 16 | If you believe you have found a security vulnerability in this repository, 17 | please report it to . 18 | 19 | Please do not report security vulnerabilities through public channels, like 20 | GitHub issues, discussions, or pull requests. 21 | 22 | Please include as much of the information listed below as you can to help us 23 | better understand and resolve the issue: 24 | 25 | - the type of issue (e.g., buffer overflow, SQL injection, or cross-site 26 | scripting) 27 | - full paths of source file(s) related to the manifestation of the issue 28 | - the location of the affected source code (tag/branch/commit or direct URL) 29 | - any special configuration required to reproduce the issue 30 | - step-by-step instructions to reproduce the issue 31 | - proof-of-concept or exploit code (if possible) 32 | - impact of the issue, including how an attacker might exploit the issue 33 | 34 | This information will help us triage your report more quickly. 35 | -------------------------------------------------------------------------------- /benchmark/euneus_benchmarker.erl: -------------------------------------------------------------------------------- 1 | -module(euneus_benchmarker). 2 | 3 | %% -------------------------------------------------------------------- 4 | %% API function exports 5 | %% -------------------------------------------------------------------- 6 | 7 | -export([bootstrap/0]). 8 | -export([encode_benchmark/0]). 9 | -export([decode_benchmark/0]). 10 | 11 | %% -------------------------------------------------------------------- 12 | %% API functions 13 | %% -------------------------------------------------------------------- 14 | 15 | -spec bootstrap() -> ok. 16 | bootstrap() -> 17 | io:format( 18 | os:cmd( 19 | "cd " ++ code:lib_dir(erlperf) ++ 20 | " && " 21 | "rebar3 escriptize" 22 | ) 23 | ). 24 | 25 | -spec encode_benchmark() -> ok. 26 | encode_benchmark() -> 27 | Data = read_decoded_data_dir_files(), 28 | Reports = erlperf:benchmark( 29 | [ 30 | % #Fun 31 | #{ 32 | runner => fun(ok) -> 33 | lists:foreach( 34 | fun({_Filename, Term}) -> 35 | euneus:encode(Term, #{}), 36 | ok 37 | end, 38 | Data 39 | ) 40 | end, 41 | init_runner => "ok." 42 | }, 43 | % #Fun 44 | #{ 45 | runner => fun(ok) -> 46 | lists:foreach( 47 | fun({_Filename, Term}) -> 48 | jiffy:encode(Term, []), 49 | ok 50 | end, 51 | Data 52 | ) 53 | end, 54 | init_runner => "ok." 55 | }, 56 | % #Fun 57 | #{ 58 | runner => fun(ok) -> 59 | lists:foreach( 60 | fun({_Filename, Term}) -> 61 | thoas:encode(Term, #{}), 62 | ok 63 | end, 64 | Data 65 | ) 66 | end, 67 | init_runner => "ok." 68 | } 69 | ], 70 | #{report => full}, 71 | undefined 72 | ), 73 | io:format( 74 | erlperf_cli:format( 75 | Reports, 76 | #{format => full} 77 | ) 78 | ). 79 | 80 | -spec decode_benchmark() -> ok. 81 | decode_benchmark() -> 82 | Files = read_data_dir_files(), 83 | Reports = erlperf:benchmark( 84 | [ 85 | % #Fun 86 | #{ 87 | runner => fun(ok) -> 88 | lists:foreach( 89 | fun({_Filename, JSON}) -> 90 | euneus:decode(JSON, #{}), 91 | ok 92 | end, 93 | Files 94 | ) 95 | end, 96 | init_runner => "ok." 97 | }, 98 | % #Fun 99 | #{ 100 | runner => fun(ok) -> 101 | lists:foreach( 102 | fun({_Filename, JSON}) -> 103 | jiffy:decode(JSON, [return_maps]), 104 | ok 105 | end, 106 | Files 107 | ) 108 | end, 109 | init_runner => "ok." 110 | }, 111 | % #Fun 112 | #{ 113 | runner => fun(ok) -> 114 | lists:foreach( 115 | fun({_Filename, JSON}) -> 116 | {ok, _} = thoas:decode(JSON, #{}), 117 | ok 118 | end, 119 | Files 120 | ) 121 | end, 122 | init_runner => "ok." 123 | } 124 | ], 125 | #{report => full}, 126 | undefined 127 | ), 128 | io:format( 129 | erlperf_cli:format( 130 | Reports, 131 | #{format => full} 132 | ) 133 | ). 134 | 135 | %% -------------------------------------------------------------------- 136 | %% Internal functions 137 | %% -------------------------------------------------------------------- 138 | 139 | read_decoded_data_dir_files() -> 140 | map_data_dir_files( 141 | fun({Filename, JSON}) -> 142 | {Filename, euneus:decode(JSON)} 143 | end 144 | ). 145 | 146 | read_data_dir_files() -> 147 | map_data_dir_files(fun({Filename, JSON}) -> {Filename, JSON} end). 148 | 149 | map_data_dir_files(Callback) -> 150 | {ok, CWD} = file:get_cwd(), 151 | DataDir = filename:join([CWD, "test", "euneus_benchmarker_SUITE_data"]), 152 | {ok, Files} = file:list_dir(DataDir), 153 | [ 154 | Callback({ 155 | Filename, 156 | read_data_dir_file(DataDir, Filename) 157 | }) 158 | || Filename <- Files 159 | ]. 160 | 161 | read_data_dir_file(DataDir, Filename) -> 162 | AbsFilename = filename:join(DataDir, Filename), 163 | {ok, Binary} = file:read_file(AbsFilename), 164 | Binary. 165 | -------------------------------------------------------------------------------- /elvis.config: -------------------------------------------------------------------------------- 1 | [ 2 | {elvis, [ 3 | {config, [ 4 | #{ 5 | dirs => ["src"], 6 | filter => "*.erl", 7 | ruleset => erl_files_strict, 8 | rules => [ 9 | {elvis_style, dont_repeat_yourself, #{min_complexity => 15}}, 10 | {elvis_style, atom_naming_convention, #{ 11 | regex => "^([a-z][a-z_0-9]*_?)*(_SUITE)?$" 12 | }}, 13 | {elvis_style, function_naming_convention, #{ 14 | regex => "^([a-z][a-z_0-9]*_?)*(_SUITE)?$" 15 | }}, 16 | {elvis_style, no_macros, #{ 17 | allow => [] 18 | }}, 19 | {elvis_style, max_function_length, #{max_length => 65}}, 20 | {elvis_style, no_throw, disable} 21 | ] 22 | }, 23 | #{ 24 | dirs => ["test"], 25 | filter => "*.erl", 26 | ruleset => erl_files_strict, 27 | rules => [ 28 | {elvis_style, no_macros, #{ 29 | allow => [ 30 | 'assert', 31 | 'assertEqual', 32 | 'assertMatch', 33 | 'assertError', 34 | 'assertNotException' 35 | ] 36 | }}, 37 | {elvis_style, max_function_length, #{max_length => 65}} 38 | ] 39 | }, 40 | #{ 41 | dirs => ["."], 42 | filter => "elvis.config", 43 | ruleset => elvis_config 44 | }, 45 | #{ 46 | dirs => ["."], 47 | filter => "rebar.config", 48 | ruleset => rebar_config 49 | } 50 | ]} 51 | ]} 52 | ]. 53 | -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | {minimum_otp_vsn, "24"}. 2 | 3 | {erl_opts, [ 4 | debug_info, 5 | warnings_as_errors, 6 | warn_missing_spec 7 | ]}. 8 | 9 | {dialyzer, [ 10 | {plt_apps, all_deps}, 11 | {plt_extra_apps, [ 12 | common_test, 13 | eunit 14 | ]}, 15 | {warnings, [ 16 | unknown, 17 | unmatched_returns 18 | ]} 19 | ]}. 20 | 21 | {deps, []}. 22 | 23 | {project_plugins, [ 24 | {rebar3_hex, "7.0.9"}, 25 | {erlfmt, "1.6.2"}, 26 | {rebar3_lint, "3.2.6"}, 27 | {rebar3_hank, "1.4.1"}, 28 | {rebar3_ex_doc, "0.2.28"} 29 | ]}. 30 | 31 | {erlfmt, [ 32 | write, 33 | {print_width, 98}, 34 | {files, [ 35 | "elvis.config", 36 | "rebar.config", 37 | "benchmark/**/*.erl", 38 | "src/*.app.src", 39 | "src/**/*.erl", 40 | "test/**/*.erl" 41 | ]}, 42 | {exclude_files, []} 43 | ]}. 44 | 45 | {hex, [{doc, #{provider => ex_doc}}]}. 46 | 47 | {ex_doc, [ 48 | {extras, [ 49 | {'README.md', #{title => <<"Overview">>}}, 50 | {'LICENSE.md', #{title => <<"License">>}}, 51 | {'CHANGELOG.md', #{title => <<"Changelog">>}}, 52 | {'CODE_OF_CONDUCT.md', #{title => <<"Code of Conduct">>}}, 53 | {'CONTRIBUTING.md', #{title => <<"Contributing">>}}, 54 | {'SECURITY.md', #{title => <<"Security">>}} 55 | ]}, 56 | {main, <<"README.md">>}, 57 | {homepage_url, <<"https://github.com/williamthome/euneus">>}, 58 | {source_url, <<"https://github.com/williamthome/euneus">>}, 59 | {api_reference, false}, 60 | {prefix_ref_vsn_with_v, false} 61 | ]}. 62 | 63 | {profiles, [ 64 | {default, [ 65 | {xref_checks, [ 66 | exports_not_used 67 | ]}, 68 | {erl_opts, [ 69 | debug_info, 70 | nowarn_missing_spec, 71 | warnings_as_errors 72 | ]} 73 | ]}, 74 | {test, [ 75 | {dialyzer, [ 76 | {plt_extra_apps, [ 77 | common_test, 78 | eunit, 79 | doctest, 80 | jiffy, 81 | thoas 82 | ]} 83 | ]}, 84 | {deps, [ 85 | {json_polyfill, "0.2.1"}, 86 | {doctest, "0.13.1"}, 87 | {jiffy, "1.1.2"}, 88 | {thoas, "1.2.1"} 89 | ]}, 90 | {cover_enabled, true}, 91 | {cover_opts, [verbose]}, 92 | {erl_opts, [ 93 | debug_info, 94 | nowarn_missing_spec, 95 | warnings_as_errors 96 | ]}, 97 | {xref_checks, []} 98 | ]}, 99 | {benchmark, [ 100 | {deps, [ 101 | {erlperf, "2.3.0"}, 102 | {jiffy, "1.1.2"}, 103 | {thoas, "1.2.1"} 104 | ]}, 105 | {extra_src_dirs, [ 106 | {"benchmark", [{recursive, true}]} 107 | ]} 108 | ]} 109 | ]}. 110 | 111 | {alias, [ 112 | {ci, [ 113 | {fmt, "--check"}, 114 | lint, 115 | hank, 116 | xref, 117 | {do, "default as test dialyzer"}, 118 | eunit, 119 | ct, 120 | {cover, "--min_coverage 90"}, 121 | ex_doc 122 | ]}, 123 | {polyfill_ci, [ 124 | lint, 125 | hank, 126 | xref, 127 | eunit, 128 | ct 129 | ]} 130 | ]}. 131 | 132 | {eunit_opts, [no_tty, {report, {doctest_eunit_report, []}}]}. 133 | -------------------------------------------------------------------------------- /rebar.lock: -------------------------------------------------------------------------------- 1 | []. 2 | -------------------------------------------------------------------------------- /src/euneus.app.src: -------------------------------------------------------------------------------- 1 | {application, euneus, [ 2 | {description, 3 | "An incredibly flexible and performant JSON parser, generator and formatter in pure Erlang"}, 4 | {vsn, "2.4.0"}, 5 | {registered, []}, 6 | {applications, [ 7 | kernel, 8 | stdlib 9 | ]}, 10 | {env, []}, 11 | {modules, []}, 12 | {licenses, ["Apache-2.0"]}, 13 | {links, [ 14 | {"GitHub", "https://github.com/williamthome/euneus"}, 15 | {"Sponsor", "https://github.com/sponsors/williamthome"} 16 | ]} 17 | ]}. 18 | -------------------------------------------------------------------------------- /src/euneus.erl: -------------------------------------------------------------------------------- 1 | -module(euneus). 2 | 3 | %% -------------------------------------------------------------------- 4 | %% API function exports 5 | %% -------------------------------------------------------------------- 6 | 7 | -export([encode/1]). 8 | -export([encode/2]). 9 | -export([encode_to_iodata/1]). 10 | -export([encode_to_iodata/2]). 11 | -export([decode/1]). 12 | -export([decode/2]). 13 | -export([decode_iodata/1]). 14 | -export([decode_iodata/2]). 15 | -export([decode_stream_start/1]). 16 | -export([decode_stream_start/2]). 17 | -export([decode_stream_continue/2]). 18 | -export([decode_stream_end/1]). 19 | -export([minify/1]). 20 | -export([minify_to_iodata/1]). 21 | -export([format/2]). 22 | -export([format_to_iodata/2]). 23 | 24 | % 25 | 26 | -ignore_xref([encode/1]). 27 | -ignore_xref([encode/2]). 28 | -ignore_xref([encode_to_iodata/1]). 29 | -ignore_xref([encode_to_iodata/2]). 30 | -ignore_xref([decode/1]). 31 | -ignore_xref([decode/2]). 32 | -ignore_xref([decode_iodata/1]). 33 | -ignore_xref([decode_iodata/2]). 34 | -ignore_xref([decode_stream_start/1]). 35 | -ignore_xref([decode_stream_start/2]). 36 | -ignore_xref([decode_stream_continue/2]). 37 | -ignore_xref([decode_stream_end/1]). 38 | -ignore_xref([minify/1]). 39 | -ignore_xref([minify_to_iodata/1]). 40 | -ignore_xref([format/2]). 41 | -ignore_xref([format_to_iodata/2]). 42 | 43 | %% -------------------------------------------------------------------- 44 | %% Doctest 45 | %% -------------------------------------------------------------------- 46 | 47 | -if(?OTP_RELEASE >= 27). 48 | -ifdef(TEST). 49 | -include_lib("eunit/include/eunit.hrl"). 50 | doctest_test() -> doctest:module(?MODULE). 51 | -endif. 52 | -endif. 53 | 54 | %% -------------------------------------------------------------------- 55 | %% API functions 56 | %% -------------------------------------------------------------------- 57 | 58 | -spec encode(Term) -> binary() when 59 | Term :: term(). 60 | %% @doc Encodes a term into a binary JSON. 61 | %% 62 | %% Example: 63 | %% 64 | %% ``` 65 | %% 1> euneus:encode(foo). 66 | %% <<"\"foo\"">> 67 | %% ''' 68 | encode(Term) -> 69 | encode(Term, #{}). 70 | 71 | -spec encode(Term, Options) -> binary() when 72 | Term :: term(), 73 | Options :: euneus_encoder:options(). 74 | %% @doc Encodes a term into a binary JSON. 75 | %% 76 | %% Example: 77 | %% 78 | %% ``` 79 | %% 1> euneus:encode(foo, #{}). 80 | %% <<"\"foo\"">> 81 | %% ''' 82 | encode(Term, Opts) -> 83 | iolist_to_binary(euneus_encoder:encode(Term, Opts)). 84 | 85 | -spec encode_to_iodata(Term) -> iodata() when 86 | Term :: term(). 87 | %% @doc Encodes a term into an iodata JSON. 88 | %% 89 | %% Example: 90 | %% 91 | %% ``` 92 | %% 1> euneus:encode_to_iodata(foo). 93 | %% [$", <<"foo">>, $"] 94 | %% ''' 95 | encode_to_iodata(Term) -> 96 | encode_to_iodata(Term, #{}). 97 | 98 | -spec encode_to_iodata(Term, Options) -> iodata() when 99 | Term :: term(), 100 | Options :: euneus_encoder:options(). 101 | %% @doc Encodes a term into an iodata JSON. 102 | %% 103 | %% Example: 104 | %% 105 | %% ``` 106 | %% 1> euneus:encode_to_iodata(foo, #{}). 107 | %% [$", <<"foo">>, $"] 108 | %% ''' 109 | encode_to_iodata(Term, Opts) -> 110 | euneus_encoder:encode(Term, Opts). 111 | 112 | -spec decode(JSON) -> term() when 113 | JSON :: binary(). 114 | %% @doc Decodes a binary JSON into a term. 115 | %% 116 | %% Example: 117 | %% 118 | %% ``` 119 | %% 1> euneus:decode(<<"\"foo\"">>). 120 | %% <<"foo">> 121 | %% ''' 122 | decode(JSON) -> 123 | decode(JSON, #{}). 124 | 125 | -spec decode(JSON, Options) -> term() when 126 | JSON :: binary(), 127 | Options :: euneus_decoder:options(). 128 | %% @doc Decodes a binary JSON into a term. 129 | %% 130 | %% Example: 131 | %% 132 | %% ``` 133 | %% 1> euneus:decode(<<"\"foo\"">>, #{}). 134 | %% <<"foo">> 135 | %% ''' 136 | decode(JSON, Opts) -> 137 | euneus_decoder:decode(JSON, Opts). 138 | 139 | -spec decode_iodata(JSON) -> term() when 140 | JSON :: iodata(). 141 | %% @doc Decodes an iodata JSON into a term. 142 | %% 143 | %% Example: 144 | %% 145 | %% ``` 146 | %% 1> euneus:decode_iodata([$", <<"foo">>, $"]). 147 | %% <<"foo">> 148 | %% ''' 149 | decode_iodata(JSON) -> 150 | decode_iodata(JSON, #{}). 151 | 152 | -spec decode_iodata(JSON, Options) -> term() when 153 | JSON :: iodata(), 154 | Options :: euneus_decoder:options(). 155 | %% @doc Decodes an iodata JSON into a term. 156 | %% 157 | %% Example: 158 | %% 159 | %% ``` 160 | %% 1> euneus:decode_iodata([$", <<"foo">>, $"], #{}). 161 | %% <<"foo">> 162 | %% ''' 163 | decode_iodata(JSON, Opts) -> 164 | euneus_decoder:decode(iolist_to_binary(JSON), Opts). 165 | 166 | -spec decode_stream_start(JSON) -> Result when 167 | JSON :: binary(), 168 | Result :: euneus_decoder:stream_result(). 169 | %% @equiv decode_stream_start(JSON, #{}) 170 | decode_stream_start(JSON) -> 171 | decode_stream_start(JSON, #{}). 172 | 173 | -spec decode_stream_start(JSON, Options) -> Result when 174 | JSON :: binary(), 175 | Options :: euneus_decoder:options(), 176 | Result :: euneus_decoder:stream_result(). 177 | %% @equiv euneus_decoder:stream_start(JSON, Options) 178 | %% 179 | %% @doc Begin parsing a stream of bytes of a JSON value. 180 | decode_stream_start(JSON, Opts) -> 181 | euneus_decoder:stream_start(JSON, Opts). 182 | 183 | -spec decode_stream_continue(JSON, State) -> Result when 184 | JSON :: binary() | end_of_input, 185 | State :: euneus_decoder:stream_state(), 186 | Result :: euneus_decoder:stream_result(). 187 | %% @equiv euneus_decoder:stream_continue(JSON, State) 188 | %% 189 | %% @doc Continue parsing a stream of bytes of a JSON value. 190 | %% 191 | %% Example: 192 | %% 193 | %% ``` 194 | %% 1> begin 195 | %% .. {continue, State} = euneus:decode_stream_start(<<"{\"foo\":">>), 196 | %% .. euneus:decode_stream_continue(<<"1}">>, State) 197 | %% .. end. 198 | %% {end_of_input,#{<<"foo">> => 1}} 199 | %% ''' 200 | decode_stream_continue(JSON, State) -> 201 | euneus_decoder:stream_continue(JSON, State). 202 | 203 | -spec decode_stream_end(State) -> Result when 204 | State :: euneus_decoder:stream_state(), 205 | Result :: {end_of_input, term()}. 206 | %% @equiv euneus_decoder:stream_continue(end_of_input, State) 207 | %% 208 | %% @doc Ends parsing a stream of bytes of a JSON value. 209 | %% 210 | %% Example: 211 | %% 212 | %% ``` 213 | %% 1> begin 214 | %% .. {continue, State} = euneus:decode_stream_start(<<"123">>), 215 | %% .. euneus:decode_stream_end(State) 216 | %% .. end. 217 | %% {end_of_input,123} 218 | %% ''' 219 | decode_stream_end(State) -> 220 | {end_of_input, Term} = euneus_decoder:stream_continue(end_of_input, State), 221 | {end_of_input, Term}. 222 | 223 | -spec minify(JSON) -> binary() when 224 | JSON :: binary(). 225 | %% @equiv iolist_to_binary(minify_to_iodata(JSON)) 226 | %% 227 | %% @doc Minifies a binary JSON. 228 | %% 229 | %% Example: 230 | %% 231 | %% ``` 232 | %% 1> euneus:minify(<<" \n{\"foo\" : [ true , \n null ] \n } ">>). 233 | %% <<"{\"foo\":[true,null]}">> 234 | %% ''' 235 | minify(JSON) -> 236 | iolist_to_binary(minify_to_iodata(JSON)). 237 | 238 | -spec minify_to_iodata(JSON) -> iodata() when 239 | JSON :: binary(). 240 | %% @doc Minifies a binary JSON. 241 | minify_to_iodata(JSON) -> 242 | euneus_formatter:format(JSON, #{ 243 | indent_type => spaces, 244 | indent_width => 0, 245 | spaced_values => false, 246 | crlf => none 247 | }). 248 | 249 | -spec format(JSON, Options) -> binary() when 250 | JSON :: binary(), 251 | Options :: euneus_formatter:options(). 252 | %% @equiv iolist_to_binary(format(JSON, Options)) 253 | %% 254 | %% @doc Formats a binary JSON. 255 | %% 256 | %% Example: 257 | %% 258 | %% ``` 259 | %% 1> Opts = #{ 260 | %% .. indent_type => tabs, 261 | %% .. indent_width => 1, 262 | %% .. spaced_values => true, 263 | %% .. crlf => n 264 | %% .. }. 265 | %% #{indent_type => tabs,indent_width => 1,spaced_values => true, crlf => n} 266 | %% 2> euneus:format(<<" \n{\"foo\" : [ true , \n null ] \n } ">>, Opts). 267 | %% <<"{\n\t\"foo\": [\n\t\ttrue,\n\t\tnull\n\t]\n}">> 268 | %% ''' 269 | format(JSON, Opts) -> 270 | iolist_to_binary(format_to_iodata(JSON, Opts)). 271 | 272 | -spec format_to_iodata(JSON, Options) -> iodata() when 273 | JSON :: binary(), 274 | Options :: euneus_formatter:options(). 275 | %% @doc Formats a binary JSON. 276 | format_to_iodata(JSON, Opts) -> 277 | euneus_formatter:format(JSON, Opts). 278 | -------------------------------------------------------------------------------- /src/euneus_formatter.erl: -------------------------------------------------------------------------------- 1 | -module(euneus_formatter). 2 | 3 | %% -------------------------------------------------------------------- 4 | %% API function exports 5 | %% -------------------------------------------------------------------- 6 | 7 | -export([format/2]). 8 | 9 | %% -------------------------------------------------------------------- 10 | %% Type exports 11 | %% -------------------------------------------------------------------- 12 | 13 | -export_type([options/0]). 14 | 15 | %% -------------------------------------------------------------------- 16 | %% Types 17 | %% -------------------------------------------------------------------- 18 | 19 | -type options() :: #{ 20 | indent_type := tabs | spaces, 21 | indent_width := non_neg_integer(), 22 | spaced_values := boolean(), 23 | crlf := crlf() 24 | }. 25 | 26 | -type crlf() :: r | n | rn | none. 27 | 28 | -record(state, { 29 | depth :: non_neg_integer(), 30 | indent :: binary(), 31 | spaces :: binary(), 32 | crlf :: crlf() 33 | }). 34 | 35 | %% -------------------------------------------------------------------- 36 | %% API functions 37 | %% -------------------------------------------------------------------- 38 | 39 | -spec format(JSON, Options) -> iodata() when 40 | JSON :: binary(), 41 | Options :: options(). 42 | %% @doc Formats a binary JSON. 43 | %% 44 | %% Option details: 45 | %% 46 | %%
    47 | %%
    48 | %%

    Note

    49 | %% There is no default for any option, all are required. 50 | %%
    51 | %%
  • 52 | %% `indent_type' - Indent using `tabs' or `spaces'. 53 | %% 54 | %%
      55 | %%
    • 56 | %% `tabs' - The indent char will be `$\t'. 57 | %% 58 | %%
    • 59 | %%
    • 60 | %% `spaces' - The indent char will be `$\s'. 61 | %% 62 | %%
    • 63 | %%
    64 | %% 65 | %%
  • 66 | %%
  • 67 | %% `indent_width' - The `indent_type' will be copied N times based on it. 68 | %% 69 | %%
  • 70 | %%
  • 71 | %% `spaced_values' - Defines if keys and values of objects should be 72 | %% spaced by one `$\s' char. 73 | %% 74 | %%
  • 75 | %%
  • 76 | %% `crlf' - Defines the Carriage Return/Line Feed. 77 | %% 78 | %%
      79 | %%
    • 80 | %% `r' - The CRLF will be `<<$\r>>'. 81 | %% 82 | %%
    • 83 | %%
    • 84 | %% `n' - The CRLF will be `<<$\n>>'. 85 | %% 86 | %%
    • 87 | %%
    • 88 | %% `rn' - The CRLF will be `<<$\r, $\n>>'. 89 | %% 90 | %%
    • 91 | %%
    • 92 | %% `none' - The CRLF will be `<<>>'. 93 | %% 94 | %%
    • 95 | %%
    96 | %%
  • 97 | %%
98 | format(JSON, Opts) when is_binary(JSON), is_map(Opts) -> 99 | do_format(JSON, new_state(Opts)). 100 | 101 | %% -------------------------------------------------------------------- 102 | %% Internal functions 103 | %% -------------------------------------------------------------------- 104 | 105 | % State 106 | 107 | new_state(Opts) -> 108 | #state{ 109 | depth = 0, 110 | indent = parse_indent( 111 | maps:get(indent_type, Opts), 112 | maps:get(indent_width, Opts) 113 | ), 114 | spaces = parse_spaces(maps:get(spaced_values, Opts)), 115 | crlf = maps:get(crlf, Opts) 116 | }. 117 | 118 | parse_indent(Type, Width) when is_integer(Width), Width >= 0 -> 119 | binary:copy(parse_indent_type(Type), Width). 120 | 121 | parse_indent_type(tabs) -> 122 | <<$\t>>; 123 | parse_indent_type(spaces) -> 124 | <<$\s>>. 125 | 126 | parse_spaces(true) -> 127 | <<$\s>>; 128 | parse_spaces(false) -> 129 | <<>>. 130 | 131 | incr_depth(State) -> 132 | State#state{depth = State#state.depth + 1}. 133 | 134 | decr_depth(#state{depth = Depth} = State) when Depth > 0 -> 135 | State#state{depth = Depth - 1}. 136 | 137 | % Format 138 | 139 | do_format(<<$\s, Rest/binary>>, State) -> 140 | do_format(Rest, State); 141 | do_format(<<$\t, Rest/binary>>, State) -> 142 | do_format(Rest, State); 143 | do_format(<<$\r, Rest/binary>>, State) -> 144 | do_format(Rest, State); 145 | do_format(<<$\n, Rest/binary>>, State) -> 146 | do_format(Rest, State); 147 | do_format(<<$", Rest0/binary>>, State) -> 148 | {Str, Rest} = string(Rest0), 149 | [Str | do_format(Rest, State)]; 150 | do_format(<<$:, Rest/binary>>, State) -> 151 | [$:, spaces(State) | do_format(Rest, State)]; 152 | do_format(<<$,, Rest/binary>>, State) -> 153 | [$,, new_line(State) | do_format(Rest, State)]; 154 | do_format(<<"true", Rest/binary>>, State) -> 155 | [<<"true">> | do_format(Rest, State)]; 156 | do_format(<<"false", Rest/binary>>, State) -> 157 | [<<"false">> | do_format(Rest, State)]; 158 | do_format(<<"null", Rest/binary>>, State) -> 159 | [<<"null">> | do_format(Rest, State)]; 160 | do_format(<<${, Rest/binary>>, State0) -> 161 | State = incr_depth(State0), 162 | [${, new_line(State) | do_format(Rest, State)]; 163 | do_format(<<$}, Rest/binary>>, State0) -> 164 | State = decr_depth(State0), 165 | [new_line(State), $} | do_format(Rest, State)]; 166 | do_format(<<$[, Rest/binary>>, State0) -> 167 | State = incr_depth(State0), 168 | [$[, new_line(State) | do_format(Rest, State)]; 169 | do_format(<<$], Rest/binary>>, State0) -> 170 | State = decr_depth(State0), 171 | [new_line(State), $] | do_format(Rest, State)]; 172 | do_format(<>, State) -> 173 | [Char | do_format(Rest, State)]; 174 | do_format(<<>>, _State) -> 175 | []. 176 | 177 | new_line(State) -> 178 | do_new_line(State#state.crlf, State). 179 | 180 | do_new_line(r, State) -> 181 | <<$\r, (indent(State))/binary>>; 182 | do_new_line(n, State) -> 183 | <<$\n, (indent(State))/binary>>; 184 | do_new_line(rn, State) -> 185 | <<$\r, $\n, (indent(State))/binary>>; 186 | do_new_line(none, _State) -> 187 | <<>>. 188 | 189 | indent(State) -> 190 | binary:copy(State#state.indent, State#state.depth). 191 | 192 | spaces(State) -> 193 | State#state.spaces. 194 | 195 | string(Rest0) -> 196 | {Len, Rest} = find_string_end(Rest0, 0), 197 | {<<$", (binary_part(Rest0, 0, Len))/binary, $">>, Rest}. 198 | 199 | find_string_end(<<$\\, $", Rest/binary>>, Len) -> 200 | find_string_end(Rest, Len + 2); 201 | find_string_end(<<$", Rest/binary>>, Len) -> 202 | {Len, Rest}; 203 | find_string_end(<<_, Rest/binary>>, Len) -> 204 | find_string_end(Rest, Len + 1). 205 | -------------------------------------------------------------------------------- /test/euneus_SUITE.erl: -------------------------------------------------------------------------------- 1 | -module(euneus_SUITE). 2 | -behaviour(ct_suite). 3 | -include_lib("stdlib/include/assert.hrl"). 4 | -compile([export_all, nowarn_export_all]). 5 | 6 | % 7 | 8 | -elvis([{elvis_style, dont_repeat_yourself, disable}]). 9 | 10 | %% -------------------------------------------------------------------- 11 | %% Behaviour (ct_suite) callbacks 12 | %% -------------------------------------------------------------------- 13 | 14 | all() -> 15 | [ 16 | Fun 17 | || {Fun, 1} <- ?MODULE:module_info(exports), 18 | re:run(atom_to_binary(Fun), <<".*_test$">>) =/= nomatch 19 | ]. 20 | 21 | %% -------------------------------------------------------------------- 22 | %% Tests 23 | %% -------------------------------------------------------------------- 24 | 25 | encode_test(Config) when is_list(Config) -> 26 | [ 27 | ?assertEqual(<<"[\"foo\"]">>, euneus:encode([foo])), 28 | ?assertEqual(<<"[\"foo\"]">>, euneus:encode([foo], #{})) 29 | ]. 30 | 31 | encode_to_iodata_test(Config) when is_list(Config) -> 32 | [ 33 | ?assertEqual([$[, [$", <<"foo">>, $"], $]], euneus:encode_to_iodata([foo])), 34 | ?assertEqual([$[, [$", <<"foo">>, $"], $]], euneus:encode_to_iodata([foo], #{})) 35 | ]. 36 | 37 | decode_test(Config) when is_list(Config) -> 38 | [ 39 | ?assertEqual([<<"foo">>], euneus:decode(<<"[\"foo\"]">>)), 40 | ?assertEqual([<<"foo">>], euneus:decode(<<"[\"foo\"]">>, #{})) 41 | ]. 42 | 43 | decode_iodata_test(Config) when is_list(Config) -> 44 | [ 45 | ?assertEqual([<<"foo">>], euneus:decode_iodata([$[, [$", <<"foo">>, $"], $]])), 46 | ?assertEqual([<<"foo">>], euneus:decode_iodata([$[, [$", <<"foo">>, $"], $]], #{})) 47 | ]. 48 | 49 | decode_stream_test(Config) when is_list(Config) -> 50 | {continue, State1} = euneus:decode_stream_start(<<"{\"foo\":">>), 51 | {continue, State2} = euneus:decode_stream_start(<<"123">>), 52 | [ 53 | ?assertEqual( 54 | {end_of_input, #{<<"foo">> => 1}}, euneus:decode_stream_continue(<<"1}">>, State1) 55 | ), 56 | ?assertEqual( 57 | {end_of_input, 123}, euneus:decode_stream_end(State2) 58 | ) 59 | ]. 60 | 61 | minify_test(Config) when is_list(Config) -> 62 | ?assertEqual( 63 | <<"{\"foo\":\"bar\",\"0\":0,[null,true,false,0.001,\"foo\",{\"foo\":0.0001]}">>, 64 | euneus:minify(<< 65 | "{\"foo\" : \"bar\",\"0\" :\n 0, [ null, \ntrue, " 66 | "false, 0.001, \"foo\" \n, {\n \"foo\" \n : \n 0.0001 \n]}" 67 | >>) 68 | ). 69 | -------------------------------------------------------------------------------- /test/euneus_benchmarker_SUITE.erl: -------------------------------------------------------------------------------- 1 | -module(euneus_benchmarker_SUITE). 2 | -behaviour(ct_suite). 3 | -include_lib("stdlib/include/assert.hrl"). 4 | -compile([export_all, nowarn_export_all]). 5 | 6 | %% -------------------------------------------------------------------- 7 | %% Behaviour (ct_suite) callbacks 8 | %% -------------------------------------------------------------------- 9 | 10 | all() -> 11 | [ 12 | Fun 13 | || {Fun, 1} <- ?MODULE:module_info(exports), 14 | re:run(atom_to_binary(Fun), <<".*_test$">>) =/= nomatch 15 | ]. 16 | 17 | %% -------------------------------------------------------------------- 18 | %% Tests 19 | %% -------------------------------------------------------------------- 20 | 21 | jiffy_decode_test(Config) when is_list(Config) -> 22 | map_data_dir_files( 23 | fun({_Filename, JSON}) -> 24 | ?assertEqual( 25 | euneus:decode(JSON, #{}), 26 | jiffy:decode(JSON, [return_maps]) 27 | ) 28 | end, 29 | get_data_dir(Config) 30 | ). 31 | 32 | thoas_decode_test(Config) when is_list(Config) -> 33 | map_data_dir_files( 34 | fun({_Filename, JSON}) -> 35 | ?assertEqual( 36 | euneus:decode(JSON, #{}), 37 | element(2, thoas:decode(JSON, #{})) 38 | ) 39 | end, 40 | get_data_dir(Config) 41 | ). 42 | 43 | % We cannot test for equality here since keys of other libs are not sortable. 44 | encode_test(Config) when is_list(Config) -> 45 | Data = read_decoded_data_dir_files(get_data_dir(Config)), 46 | lists:foreach( 47 | fun({_Filename, Term}) -> 48 | _ = euneus:encode(Term, #{}), 49 | ?assert(true) 50 | end, 51 | Data 52 | ). 53 | 54 | %% -------------------------------------------------------------------- 55 | %% Test support 56 | %% -------------------------------------------------------------------- 57 | 58 | read_decoded_data_dir_files(DataDir) -> 59 | map_data_dir_files( 60 | fun({Filename, JSON}) -> 61 | {Filename, euneus:decode(JSON)} 62 | end, 63 | DataDir 64 | ). 65 | 66 | get_data_dir(Config) -> 67 | proplists:get_value(data_dir, Config). 68 | 69 | map_data_dir_files(Callback, DataDir) -> 70 | {ok, Files} = file:list_dir(DataDir), 71 | [ 72 | Callback({ 73 | filename:join(DataDir, Filename), 74 | read_file(filename:join(DataDir, Filename)) 75 | }) 76 | || Filename <- Files 77 | ]. 78 | 79 | read_file(Filename) -> 80 | {ok, Binary} = file:read_file(Filename), 81 | Binary. 82 | -------------------------------------------------------------------------------- /test/euneus_benchmarker_SUITE_data/blockchain.json: -------------------------------------------------------------------------------- 1 | { 2 | "txs":[ 3 | 4 | { 5 | "lock_time":0, 6 | "ver":1, 7 | "size":224, 8 | "inputs":[ 9 | { 10 | "sequence":4294967295, 11 | "prev_out":{ 12 | "spent":true, 13 | "tx_index":251046142, 14 | "type":0, 15 | "addr":"1Cz2o3kcCzWUME4yaTakC78ZmAuGmnkARX", 16 | "value":2327000, 17 | "n":0, 18 | "script":"76a914837297476f9f22b1b63aef82560b3ae0610c980388ac" 19 | }, 20 | "script":"483045022100b0f9f874293d3ea9d214411a20ce094b819ac564d3dfeeeaef651bf9b9bfb9410220665470d6c58ad5ab77ce81179efdc45a1629b592f98e93f7b45dd7d7a3591c06012103da87165824fb8bd4face2ea4cf97e3ffe8359110141096f750db876289d66223" 21 | } 22 | ], 23 | "double_spend":false, 24 | "time":1494882215, 25 | "tx_index":251067906, 26 | "vin_sz":1, 27 | "hash":"a7fd5cf3901ffd4410dd730942366658648b64119cfc8240feb3c07806703540", 28 | "vout_sz":2, 29 | "relayed_by":"127.0.0.1", 30 | "out":[ 31 | { 32 | "spent":false, 33 | "tx_index":251067906, 34 | "type":0, 35 | "addr":"1Bf226wi388ax87yCFxcijYP8iz1KCxasU", 36 | "value":29880, 37 | "n":0, 38 | "script":"76a91474e1ea3e27554771e289045c7a082045246ae86a88ac" 39 | }, 40 | { 41 | "spent":false, 42 | "tx_index":251067906, 43 | "type":0, 44 | "addr":"37McuYxfwo97fiFUwxUpj8FG3McWrWvfk2", 45 | "value":2270000, 46 | "n":1, 47 | "script":"a9143e25a34198abcbcae06cf4e235ea8de65fafba6387" 48 | } 49 | ] 50 | }, 51 | 52 | { 53 | "lock_time":0, 54 | "ver":1, 55 | "size":473, 56 | "inputs":[ 57 | { 58 | "sequence":4294967295, 59 | "prev_out":{ 60 | "spent":true, 61 | "tx_index":251057821, 62 | "type":0, 63 | "addr":"365VPevZ8zpnzvDg9e2XEufLJpDXunrL3p", 64 | "value":13386793, 65 | "n":1, 66 | "script":"a9143020953c35bd255bcfc98bdf8565e6e8486793ce87" 67 | }, 68 | "script":"0047304402200a56722de364cd46c2a863f9899f6ed668ed0a0d50e1f7795e36af7e94d9a2f202202949a294cb20bafc0b5a83d6f363d13f971a9b78898de6e10403f953ca88def101473044022049ad29cf209fbef3003a4270f2ff00bd2a992693c895483dbe96e675f1a89f0002206d310e61682c1334f46d0ca7cb4c4aed6a76b5af094592b2485d66161f329935014ccf522102ad8f2010b1d6ca1bf6d0289de8c5706dca174bfff9b551fa0a3e9961fd7896a121032cfca753d90effe3a35cb01d50bdbad05de439a28cd022f49e9108dc9a5b28fc210370a034d6ba2745681236f54334b023be6f84076fac8b3573c70e2780371e23502103844e246b4ba7e517cbaa247b10e29b59866409a8b6f97cb2d9a6fa346f472e0e210390afcc527e0b5ee39f2ac8ef5931796eaadbc32ecdd64d8fb2fbea7d7ec96cf42103b3dfce7aa0d2f4b29367076a5d2301d321a367d8fb6777080a98657bbab2c9ca56ae" 69 | } 70 | ], 71 | "double_spend":false, 72 | "time":1494882215, 73 | "tx_index":251069422, 74 | "vin_sz":1, 75 | "hash":"b56687718789d9468cd240e584d385817006c10cea4d18e9afe9b7557df2f33f", 76 | "vout_sz":2, 77 | "relayed_by":"78.68.155.43", 78 | "out":[ 79 | { 80 | "spent":false, 81 | "tx_index":251069422, 82 | "type":0, 83 | "addr":"1GDTiq92XgXaocw9yyFx1pjJBHwjd2Si1T", 84 | "value":6116700, 85 | "n":0, 86 | "script":"76a914a6e52f1d1c522aafcf2b0726a7621c5358d896a888ac" 87 | }, 88 | { 89 | "spent":false, 90 | "tx_index":251069422, 91 | "type":0, 92 | "addr":"3KsoXsw4FZN9Hm1fwQjHkcTNeDQXWYPRMu", 93 | "value":7111025, 94 | "n":1, 95 | "script":"a914c77c7f1387da8129df42715fdeeeb5f300b6bcca87" 96 | } 97 | ] 98 | }, 99 | 100 | { 101 | "lock_time":0, 102 | "ver":1, 103 | "size":1259, 104 | "inputs":[ 105 | { 106 | "sequence":4294967295, 107 | "prev_out":{ 108 | "spent":true, 109 | "tx_index":246301202, 110 | "type":0, 111 | "addr":"14rLNtnfRndYvGhuNqpRpUtPQLaeheKjHk", 112 | "value":4444444, 113 | "n":118, 114 | "script":"76a9142a3cef5a41ca75f7fdb4259938491bcee9e99b2588ac" 115 | }, 116 | "script":"483045022100cfd7ac622d25cb54304d68461049a696477f758f4fd493d1d60df1e08e6c280a02204c1712c6d7625194b0e947acefa9fdffc904b6e6c769cd47deeb78d3e3119df30121038ef6a69cb98448bda6e3e6a2b514168c0e36a7c10e88414531c4072965eff063" 117 | }, 118 | { 119 | "sequence":4294967295, 120 | "prev_out":{ 121 | "spent":true, 122 | "tx_index":247736773, 123 | "type":0, 124 | "addr":"14rLNtnfRndYvGhuNqpRpUtPQLaeheKjHk", 125 | "value":4444444, 126 | "n":91, 127 | "script":"76a9142a3cef5a41ca75f7fdb4259938491bcee9e99b2588ac" 128 | }, 129 | "script":"483045022100dcd341ac99292e4198c8c695a3cce6db1181b912093196ce217515f5272306640220011afff35bc63db46d772cd72be874658a54d3e0fc1ed0026a71edfc617a21d20121038ef6a69cb98448bda6e3e6a2b514168c0e36a7c10e88414531c4072965eff063" 130 | }, 131 | { 132 | "sequence":4294967295, 133 | "prev_out":{ 134 | "spent":true, 135 | "tx_index":247002242, 136 | "type":0, 137 | "addr":"14rLNtnfRndYvGhuNqpRpUtPQLaeheKjHk", 138 | "value":4444444, 139 | "n":107, 140 | "script":"76a9142a3cef5a41ca75f7fdb4259938491bcee9e99b2588ac" 141 | }, 142 | "script":"4830450221009cd60022558a45d341acef08b8d078e14138d6ad12259c57fa39737979194763022000a97fd165f294bda58fbbb66d03f833d8ca52644ee071d04e4e237d725d29670121038ef6a69cb98448bda6e3e6a2b514168c0e36a7c10e88414531c4072965eff063" 143 | }, 144 | { 145 | "sequence":4294967295, 146 | "prev_out":{ 147 | "spent":true, 148 | "tx_index":249742437, 149 | "type":0, 150 | "addr":"14rLNtnfRndYvGhuNqpRpUtPQLaeheKjHk", 151 | "value":4444444, 152 | "n":111, 153 | "script":"76a9142a3cef5a41ca75f7fdb4259938491bcee9e99b2588ac" 154 | }, 155 | "script":"473044022009e2d273ba3e2f319431ad32b51628e4ea365778384d07f956ee4742c0afb6a502200acea9de021de43ddd4105cbbf9501775bec4c29dd73a1a795d881e8c68cbf470121038ef6a69cb98448bda6e3e6a2b514168c0e36a7c10e88414531c4072965eff063" 156 | }, 157 | { 158 | "sequence":4294967295, 159 | "prev_out":{ 160 | "spent":true, 161 | "tx_index":249038984, 162 | "type":0, 163 | "addr":"14rLNtnfRndYvGhuNqpRpUtPQLaeheKjHk", 164 | "value":4444444, 165 | "n":121, 166 | "script":"76a9142a3cef5a41ca75f7fdb4259938491bcee9e99b2588ac" 167 | }, 168 | "script":"483045022100eb1c0e4be87609c659bc9eab60f52bc39e8e485ce571dec3efc840d66d64a1560220016a1f40fa8d06fd1577f13656c3079870a8b07903cfb01c14ba699df22c395f0121038ef6a69cb98448bda6e3e6a2b514168c0e36a7c10e88414531c4072965eff063" 169 | }, 170 | { 171 | "sequence":4294967295, 172 | "prev_out":{ 173 | "spent":true, 174 | "tx_index":245680316, 175 | "type":0, 176 | "addr":"14rLNtnfRndYvGhuNqpRpUtPQLaeheKjHk", 177 | "value":4444444, 178 | "n":125, 179 | "script":"76a9142a3cef5a41ca75f7fdb4259938491bcee9e99b2588ac" 180 | }, 181 | "script":"4830450221008682ac4ccbdb36a7b123f793e3057c99b37710a582dc446b931f5b3b4175efb502203f9d41a9130a65cee46e08f8de568d21f359d2dce05d0a26be4bc8f1c3e4396d0121038ef6a69cb98448bda6e3e6a2b514168c0e36a7c10e88414531c4072965eff063" 182 | }, 183 | { 184 | "sequence":4294967295, 185 | "prev_out":{ 186 | "spent":true, 187 | "tx_index":250412310, 188 | "type":0, 189 | "addr":"14rLNtnfRndYvGhuNqpRpUtPQLaeheKjHk", 190 | "value":4444444, 191 | "n":107, 192 | "script":"76a9142a3cef5a41ca75f7fdb4259938491bcee9e99b2588ac" 193 | }, 194 | "script":"47304402204a5c440a348b9f8ac1bba105edec0e8e6e064c93f68c4a0fcd2f7e8d12fbc524022061a62702cb7b9e01901f23c5cff0f7bd56d1bc0bc689343fff9f259782ec131b0121038ef6a69cb98448bda6e3e6a2b514168c0e36a7c10e88414531c4072965eff063" 195 | }, 196 | { 197 | "sequence":4294967295, 198 | "prev_out":{ 199 | "spent":true, 200 | "tx_index":248289092, 201 | "type":0, 202 | "addr":"14rLNtnfRndYvGhuNqpRpUtPQLaeheKjHk", 203 | "value":4444444, 204 | "n":106, 205 | "script":"76a9142a3cef5a41ca75f7fdb4259938491bcee9e99b2588ac" 206 | }, 207 | "script":"47304402201074ca23132c2c1c23f445176307195f65d045adf193f2d0704dac5dce47e28702201cb2fb0c20460a4de3f419920a810d4059b5c92fba17bde1ffe900e59e3b413f0121038ef6a69cb98448bda6e3e6a2b514168c0e36a7c10e88414531c4072965eff063" 208 | } 209 | ], 210 | "double_spend":false, 211 | "time":1494882215, 212 | "tx_index":251067907, 213 | "vin_sz":8, 214 | "hash":"9380e2a725ce0ecdf1dc3125cb2e60242daad08a75ba14407ad88757e2b7cb1d", 215 | "vout_sz":2, 216 | "relayed_by":"127.0.0.1", 217 | "out":[ 218 | { 219 | "spent":false, 220 | "tx_index":251067907, 221 | "type":0, 222 | "addr":"1MyjAo3QMCew6d7Cy1bj9j5C9gracQW8LH", 223 | "value":151468, 224 | "n":0, 225 | "script":"76a914e61d02a4c1a0ff3d8c7a577f431e77f81c6f5a6788ac" 226 | }, 227 | { 228 | "spent":false, 229 | "tx_index":251067907, 230 | "type":0, 231 | "addr":"1B21L6VCqaLy9HRHYu76vQ4Y2PbamNXSGj", 232 | "value":35252644, 233 | "n":1, 234 | "script":"76a9146de1f2d8820969f9dbd0310d900e3ec9d9245c4888ac" 235 | } 236 | ] 237 | }, 238 | 239 | { 240 | "lock_time":0, 241 | "ver":1, 242 | "size":300, 243 | "inputs":[ 244 | { 245 | "sequence":4294967295, 246 | "prev_out":{ 247 | "spent":true, 248 | "tx_index":251018984, 249 | "type":0, 250 | "addr":"33dPjT2DrjRBa6hL8xNdDS1anh9CGnc2JP", 251 | "value":300000, 252 | "n":1, 253 | "script":"a9141540caefd7eb26de1fc56c7ffa8c4784f4737eec87" 254 | }, 255 | "script":"0047304402202e848d5d10f302bfcdc443a36f46d2d31fd12daea6bd527327d094a2ce0299f8022008b9deb9611f4a43bf52845fdfc8bfc46b7088d3a3cd79b944e2ae029b641afa0147304402205abf36e332edffb30cb73d0d812f3bb5cf7a9738ec3dcd268b2b9f797337c064022054ce915bc28fdc8d3a8ecce422c94d74b9ea23372ee05957015632e1aadfb9f201475221020ac26563884b7a94892cf4d455470cb926531d2d5fb9926d6d477027303165c221025866ea732eef3017fa944a16af48316e2441e4a3a8bbac521300226f8f4cfb0c52ae" 256 | } 257 | ], 258 | "double_spend":false, 259 | "time":1494882215, 260 | "tx_index":251071134, 261 | "vin_sz":1, 262 | "hash":"79827d7745d8dfa78aa7928e172d4a1c176c8f8a32109f4eace632868ba366b1", 263 | "vout_sz":1, 264 | "relayed_by":"88.99.144.222", 265 | "out":[ 266 | { 267 | "spent":false, 268 | "tx_index":251071134, 269 | "type":0, 270 | "addr":"3HEGhkgoBPnFEe4RqCbnCGKp2yJsTQrNf7", 271 | "value":239300, 272 | "n":0, 273 | "script":"a914aa731e6e109224f382dbe39851b7662186abe2eb87" 274 | } 275 | ] 276 | }, 277 | 278 | { 279 | "lock_time":0, 280 | "ver":1, 281 | "size":225, 282 | "inputs":[ 283 | { 284 | "sequence":4294967295, 285 | "prev_out":{ 286 | "spent":true, 287 | "tx_index":250470010, 288 | "type":0, 289 | "addr":"17RQE4ZDQxFndCZGacBkMv2hXoz6Ao4P6n", 290 | "value":7125000, 291 | "n":1, 292 | "script":"76a914466e200d3b7e281b2e14d43c864d7f8fc24ea7c088ac" 293 | }, 294 | "script":"47304402203dd8b230a5a1ae87e2fe0e2987a25198fd38953beeca59e108aa5362198e398b02207ce3acc7401e11ffd2087da4e98ce6112bc9e80d19f71bc1c06b5ca76a79594d012103726e04f1a6641f30dbe49cf526e191daa0ed91b79cdca86f3b4177b63a1fbbde" 295 | } 296 | ], 297 | "double_spend":false, 298 | "time":1494882215, 299 | "tx_index":251071135, 300 | "vin_sz":1, 301 | "hash":"297bbdba8fe56bf407b62c8e71edafa7bebe3ac082b8b1c55bd434f94e106eed", 302 | "vout_sz":2, 303 | "relayed_by":"88.99.144.222", 304 | "out":[ 305 | { 306 | "spent":false, 307 | "tx_index":251071135, 308 | "type":0, 309 | "addr":"1Fpa6F3xzGC9CV9YBEt1KiNwuacd8Yuxyg", 310 | "value":5797100, 311 | "n":0, 312 | "script":"76a914a290ef02ebdfd1fee11679e6f4646db334b54abb88ac" 313 | }, 314 | { 315 | "spent":false, 316 | "tx_index":251071135, 317 | "type":0, 318 | "addr":"11PagoqBp9FiLHE3wWJtnG47Y41jvoYxc", 319 | "value":1268156, 320 | "n":1, 321 | "script":"76a9140012d978f0aaf679c908a1c9d9b3664e021d18ed88ac" 322 | } 323 | ] 324 | }, 325 | 326 | { 327 | "lock_time":0, 328 | "ver":1, 329 | "size":192, 330 | "inputs":[ 331 | { 332 | "sequence":4294967295, 333 | "prev_out":{ 334 | "spent":true, 335 | "tx_index":249639876, 336 | "type":0, 337 | "addr":"1CKAaswJseRbYwhNQ8GTbfyJV4xYYetorz", 338 | "value":26210, 339 | "n":0, 340 | "script":"76a9147c18df105dde3e540f080a50539f94d94a8c524b88ac" 341 | }, 342 | "script":"483045022100c36ab33ba8607e2f096cd5bb87de02d33a8adae01eea5a14e7d048986b1da6b202201bb6e7914065d7e297a9874635a4d94ca72dd4109ac75d300dcfdb3112b7112a0121033df928eded9fe1b41467cd931cabaebeeee61578de28302f3bfb9721149c0bf9" 343 | } 344 | ], 345 | "double_spend":false, 346 | "time":1494882215, 347 | "tx_index":251067908, 348 | "vin_sz":1, 349 | "hash":"ed1f583eda4cd2f125053cc52f6dcda4bf090d514ed14731ffd105b4576cd0e0", 350 | "vout_sz":1, 351 | "relayed_by":"51.15.77.78", 352 | "out":[ 353 | { 354 | "spent":false, 355 | "tx_index":251067908, 356 | "type":0, 357 | "addr":"1DwZpY6ESxaRvNvq5RCCDkVFQrbvPAtESb", 358 | "value":16210, 359 | "n":0, 360 | "script":"76a9148df35e251612fd6d07a2752bcbb2af36e1e2655288ac" 361 | } 362 | ] 363 | }, 364 | 365 | { 366 | "lock_time":0, 367 | "ver":1, 368 | "size":191, 369 | "inputs":[ 370 | { 371 | "sequence":4294967295, 372 | "prev_out":{ 373 | "spent":true, 374 | "tx_index":249642709, 375 | "type":0, 376 | "addr":"1CKAaswJseRbYwhNQ8GTbfyJV4xYYetorz", 377 | "value":42301, 378 | "n":1, 379 | "script":"76a9147c18df105dde3e540f080a50539f94d94a8c524b88ac" 380 | }, 381 | "script":"4730440220237a3998b55cb1015abc26196abcc5b267990bba1a955a5ee14e9159ca80bdfa02204b966b9bee759e626c41fb11f9e3d7e16c99d4a2c621f26170383fbe9e5736a70121033df928eded9fe1b41467cd931cabaebeeee61578de28302f3bfb9721149c0bf9" 382 | } 383 | ], 384 | "double_spend":false, 385 | "time":1494882215, 386 | "tx_index":251069423, 387 | "vin_sz":1, 388 | "hash":"550bdd658800e39bbcf05d53cd3059a61f0a7bdb2e7cfe5e7966fed511609760", 389 | "vout_sz":1, 390 | "relayed_by":"51.15.77.78", 391 | "out":[ 392 | { 393 | "spent":false, 394 | "tx_index":251069423, 395 | "type":0, 396 | "addr":"1DwZpY6ESxaRvNvq5RCCDkVFQrbvPAtESb", 397 | "value":32301, 398 | "n":0, 399 | "script":"76a9148df35e251612fd6d07a2752bcbb2af36e1e2655288ac" 400 | } 401 | ] 402 | }, 403 | 404 | { 405 | "lock_time":0, 406 | "ver":1, 407 | "size":192, 408 | "inputs":[ 409 | { 410 | "sequence":4294967295, 411 | "prev_out":{ 412 | "spent":true, 413 | "tx_index":249640878, 414 | "type":0, 415 | "addr":"1CKAaswJseRbYwhNQ8GTbfyJV4xYYetorz", 416 | "value":5527309, 417 | "n":1, 418 | "script":"76a9147c18df105dde3e540f080a50539f94d94a8c524b88ac" 419 | }, 420 | "script":"483045022100c1e2e936e4a9aad6b230d2fa93e7ff2463413b4008d831402f219d1a1517abce02200deadab123fd21ed27daeb6c9adbad99ad5b5cbda56ee1c41fe4eb2a847915e10121033df928eded9fe1b41467cd931cabaebeeee61578de28302f3bfb9721149c0bf9" 421 | } 422 | ], 423 | "double_spend":false, 424 | "time":1494882215, 425 | "tx_index":251069424, 426 | "vin_sz":1, 427 | "hash":"717e26e31490419c179b5df69eef2804fcf1c0df0b33d8acb19b9e585398c3be", 428 | "vout_sz":1, 429 | "relayed_by":"51.15.77.78", 430 | "out":[ 431 | { 432 | "spent":false, 433 | "tx_index":251069424, 434 | "type":0, 435 | "addr":"1DwZpY6ESxaRvNvq5RCCDkVFQrbvPAtESb", 436 | "value":5517309, 437 | "n":0, 438 | "script":"76a9148df35e251612fd6d07a2752bcbb2af36e1e2655288ac" 439 | } 440 | ] 441 | }, 442 | 443 | { 444 | "lock_time":466583, 445 | "ver":2, 446 | "size":226, 447 | "inputs":[ 448 | { 449 | "sequence":4294967294, 450 | "prev_out":{ 451 | "spent":true, 452 | "tx_index":251037372, 453 | "type":0, 454 | "addr":"1DhJkf66tyWhgk97eticf3u5serhYugCrT", 455 | "value":290000000, 456 | "n":0, 457 | "script":"76a9148b40f792f03cc13d1314dcf50260fffc8b1f92e688ac" 458 | }, 459 | "script":"483045022100bf4854c7d657fc194272dc1b18227660666d5e164c2a55d90ee72e1fb9cd6ea60220417f805e3f6d56b370fbc606a89492479a0edfdc3c71528a18e247b3db1d18100121030c041f7ef29a50edd9cbb8b7d4f0f39648eb45b36504d0f8e030ccd3484e2046" 460 | } 461 | ], 462 | "double_spend":false, 463 | "time":1494882215, 464 | "tx_index":251067909, 465 | "vin_sz":1, 466 | "hash":"70c21386a9eb45b6c5c1c9b9d8f85f697262370acbd812d0d242e59687466265", 467 | "vout_sz":2, 468 | "relayed_by":"138.201.31.13", 469 | "out":[ 470 | { 471 | "spent":false, 472 | "tx_index":251067909, 473 | "type":0, 474 | "addr":"1E5XAF3SX1GCx1RokrnvNceUGmZWP8QMu1", 475 | "value":11326740, 476 | "n":0, 477 | "script":"76a9148f74798be706ce097f4dd4df36b9b23737efbe2288ac" 478 | }, 479 | { 480 | "spent":false, 481 | "tx_index":251067909, 482 | "type":0, 483 | "addr":"13Kk45oEGt9rFJZFqSXxU3NsUDqXTQP4wb", 484 | "value":278622410, 485 | "n":1, 486 | "script":"76a914197bad86e5b8f23f0dfd32136cb9e9445c7b651788ac" 487 | } 488 | ] 489 | }, 490 | 491 | { 492 | "lock_time":0, 493 | "ver":1, 494 | "size":373, 495 | "inputs":[ 496 | { 497 | "sequence":4294967295, 498 | "prev_out":{ 499 | "spent":true, 500 | "tx_index":251031230, 501 | "type":0, 502 | "addr":"3PG8xdNEYw3SvH84htLvaNPV2V5NaJPE9N", 503 | "value":57994243, 504 | "n":1, 505 | "script":"a914ec9e3dd2dcc70ae6bc00ddb101b3769c6d68503b87" 506 | }, 507 | "script":"00483045022100bc347fa68409ff4c93b8d344b0775c8d6ce36168d6cbbec402371659171319d7022045babb00bc4f8b027839475d78034c18b2b7c5ce157c185497c1a04bc0c283d401483045022100ef0c44e5ad98f164d555e0594d7b180d8948171408228562869b9bd8a1b9e8960220778309f70793f8d33f2013fdccb0478b97bf23328d6fb8b6188857df50868a49014c69522102bf69b532e65cd381850aff1e5dd30d8ffaf75b7c97049c4018e2a1c65f7e8da22102e69156861a946dcbc3ad91d8723a9ac7bc56110378f10472ea76a2a7f1ff39602103db33c172b067a82b573e8977cb7f4727555c104031ef4c43effe90aca59453ff53ae" 508 | } 509 | ], 510 | "double_spend":false, 511 | "time":1494882216, 512 | "tx_index":251069425, 513 | "vin_sz":1, 514 | "hash":"3ff294998cd2dc356110c86a84f1daa624b34dd5f03a2cca81d366410479ee89", 515 | "vout_sz":2, 516 | "relayed_by":"72.234.155.29", 517 | "out":[ 518 | { 519 | "spent":false, 520 | "tx_index":251069425, 521 | "type":0, 522 | "addr":"1FpzCX4tkCWCprMVoCvwRvTJcoUofHMMN8", 523 | "value":650000, 524 | "n":0, 525 | "script":"76a914a2a50ee370ab1b2e8bec4f1c545fa74f0bf0275788ac" 526 | }, 527 | { 528 | "spent":false, 529 | "tx_index":251069425, 530 | "type":0, 531 | "addr":"3JXBX8M9iDF6S8kborg8Lx2jzJEQ2f1fze", 532 | "value":57272008, 533 | "n":1, 534 | "script":"a914b89dfd40d18420a4800df0d7b5bfc62a9021223787" 535 | } 536 | ] 537 | }] 538 | } 539 | -------------------------------------------------------------------------------- /test/euneus_benchmarker_SUITE_data/utf-8-unescaped.json: -------------------------------------------------------------------------------- 1 | "\nUTF-8 encoded sample plain-text file\n‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\n\nMarkus Kuhn [ˈmaʳkʊs kuːn] — 2002-07-25\n\n\nThe ASCII compatible UTF-8 encoding used in this plain-text file\nis defined in Unicode, ISO 10646-1, and RFC 2279.\n\n\nUsing Unicode/UTF-8, you can write in emails and source code things such as\n\nMathematics and sciences:\n\n ∮ E⋅da = Q, n → ∞, ∑ f(i) = ∏ g(i), ⎧⎡⎛┌─────┐⎞⎤⎫\n ⎪⎢⎜│a²+b³ ⎟⎥⎪\n ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β), ⎪⎢⎜│───── ⎟⎥⎪\n ⎪⎢⎜⎷ c₈ ⎟⎥⎪\n ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ, ⎨⎢⎜ ⎟⎥⎬\n ⎪⎢⎜ ∞ ⎟⎥⎪\n ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫), ⎪⎢⎜ ⎲ ⎟⎥⎪\n ⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪\n 2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm ⎩⎣⎝i=1 ⎠⎦⎭\n\nLinguistics and dictionaries:\n\n ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn\n Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ]\n\nAPL:\n\n ((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈\n\nNicer typography in plain text files:\n\n ╔══════════════════════════════════════════╗\n ║ ║\n ║ • ‘single’ and “double” quotes ║\n ║ ║\n ║ • Curly apostrophes: “We’ve been here” ║\n ║ ║\n ║ • Latin-1 apostrophe and accents: '´` ║\n ║ ║\n ║ • ‚deutsche‘ „Anführungszeichen“ ║\n ║ ║\n ║ • †, ‡, ‰, •, 3–4, —, −5/+5, ™, … ║\n ║ ║\n ║ • ASCII safety test: 1lI|, 0OD, 8B ║\n ║ ╭─────────╮ ║\n ║ • the euro symbol: │ 14.95 € │ ║\n ║ ╰─────────╯ ║\n ╚══════════════════════════════════════════╝\n\nCombining characters:\n\n STARGΛ̊TE SG-1, a = v̇ = r̈, a⃑ ⊥ b⃑\n\nGreek (in Polytonic):\n\n The Greek anthem:\n\n Σὲ γνωρίζω ἀπὸ τὴν κόψη\n τοῦ σπαθιοῦ τὴν τρομερή,\n σὲ γνωρίζω ἀπὸ τὴν ὄψη\n ποὺ μὲ βία μετράει τὴ γῆ.\n\n ᾿Απ᾿ τὰ κόκκαλα βγαλμένη\n τῶν ῾Ελλήνων τὰ ἱερά\n καὶ σὰν πρῶτα ἀνδρειωμένη\n χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά!\n\n From a speech of Demosthenes in the 4th century BC:\n\n Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι,\n ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς\n λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ\n τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿\n εἰς τοῦτο προήκοντα, ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ\n πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν\n οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι,\n οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν\n ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον\n τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι\n γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν\n προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους\n σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ\n τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ\n τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς\n τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον.\n\n Δημοσθένους, Γ´ ᾿Ολυνθιακὸς\n\nGeorgian:\n\n From a Unicode conference invitation:\n\n გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო\n კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს,\n ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს\n ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი,\n ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება\n ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში,\n ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში.\n\nRussian:\n\n From a Unicode conference invitation:\n\n Зарегистрируйтесь сейчас на Десятую Международную Конференцию по\n Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии.\n Конференция соберет широкий круг экспертов по вопросам глобального\n Интернета и Unicode, локализации и интернационализации, воплощению и\n применению Unicode в различных операционных системах и программных\n приложениях, шрифтах, верстке и многоязычных компьютерных системах.\n\nThai (UCS Level 2):\n\n Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese\n classic 'San Gua'):\n\n [----------------------------|------------------------]\n ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่\n สิบสองกษัตริย์ก่อนหน้าแลถัดไป สององค์ไซร้โง่เขลาเบาปัญญา\n ทรงนับถือขันทีเป็นที่พึ่ง บ้านเมืองจึงวิปริตเป็นนักหนา\n โฮจิ๋นเรียกทัพทั่วหัวเมืองมา หมายจะฆ่ามดชั่วตัวสำคัญ\n เหมือนขับไสไล่เสือจากเคหา รับหมาป่าเข้ามาเลยอาสัญ\n ฝ่ายอ้องอุ้นยุแยกให้แตกกัน ใช้สาวนั้นเป็นชนวนชื่นชวนใจ\n พลันลิฉุยกุยกีกลับก่อเหตุ ช่างอาเพศจริงหนาฟ้าร้องไห้\n ต้องรบราฆ่าฟันจนบรรลัย ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ\n\n (The above is a two-column text. If combining characters are handled\n correctly, the lines of the second column should be aligned with the\n | character above.)\n\nEthiopian:\n\n Proverbs in the Amharic language:\n\n ሰማይ አይታረስ ንጉሥ አይከሰስ።\n ብላ ካለኝ እንደአባቴ በቆመጠኝ።\n ጌጥ ያለቤቱ ቁምጥና ነው።\n ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው።\n የአፍ ወለምታ በቅቤ አይታሽም።\n አይጥ በበላ ዳዋ ተመታ።\n ሲተረጉሙ ይደረግሙ።\n ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል።\n ድር ቢያብር አንበሳ ያስር።\n ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም።\n እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም።\n የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ።\n ሥራ ከመፍታት ልጄን ላፋታት።\n ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል።\n የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ።\n ተንጋሎ ቢተፉ ተመልሶ ባፉ።\n ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው።\n እግርህን በፍራሽህ ልክ ዘርጋ።\n\nRunes:\n\n ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ\n\n (Old English, which transcribed into Latin reads 'He cwaeth that he\n bude thaem lande northweardum with tha Westsae.' and means 'He said\n that he lived in the northern land near the Western Sea.')\n\nBraille:\n\n ⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌\n\n ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞\n ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎\n ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂\n ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙\n ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑\n ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲\n\n ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲\n\n ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹\n ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞\n ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕\n ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹\n ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎\n ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎\n ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳\n ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞\n ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲\n\n (The first couple of paragraphs of \"A Christmas Carol\" by Dickens)\n\nCompact font selection example text:\n\n ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789\n abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ\n –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд\n ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა\n\nGreetings in various languages:\n\n Hello world, Καλημέρα κόσμε, コンニチハ\n\nBox drawing alignment tests: █\n ▉\n ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳\n ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳\n ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳\n ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳\n ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎\n ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏\n ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ ▗▄▖▛▀▜ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█\n ▝▀▘▙▄▟\n" 2 | -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE.erl: -------------------------------------------------------------------------------- 1 | -module(euneus_decoder_SUITE). 2 | -behaviour(ct_suite). 3 | -include_lib("stdlib/include/assert.hrl"). 4 | -compile([export_all, nowarn_export_all]). 5 | 6 | %% -------------------------------------------------------------------- 7 | %% Behaviour (ct_suite) callbacks 8 | %% -------------------------------------------------------------------- 9 | 10 | all() -> 11 | [ 12 | Fun 13 | || {Fun, 1} <- ?MODULE:module_info(exports), 14 | re:run(atom_to_binary(Fun), <<".*_test$">>) =/= nomatch 15 | ]. 16 | 17 | %% -------------------------------------------------------------------- 18 | %% Tests 19 | %% -------------------------------------------------------------------- 20 | 21 | decode_test(Config) -> 22 | DataDir = proplists:get_value(data_dir, Config), 23 | {ok, Files} = file:list_dir(DataDir), 24 | lists:foreach( 25 | fun(Filename) -> 26 | AbsFilename = filename:join(DataDir, Filename), 27 | {ok, JSON} = file:read_file(AbsFilename), 28 | assert(Filename, JSON) 29 | end, 30 | Files 31 | ). 32 | 33 | assert("y_" ++ _, JSON) -> 34 | ?assertNotException( 35 | error, 36 | Reason when 37 | Reason =:= unexpected_end; 38 | (is_tuple(Reason) andalso element(1, Reason) =:= invalid_byte); 39 | (is_tuple(Reason) andalso element(1, Reason) =:= unexpected_sequence), 40 | decode(JSON) 41 | ); 42 | assert("n_" ++ _, JSON) -> 43 | ?assertException( 44 | error, 45 | Reason when 46 | Reason =:= unexpected_end; 47 | (is_tuple(Reason) andalso element(1, Reason) =:= invalid_byte); 48 | (is_tuple(Reason) andalso element(1, Reason) =:= unexpected_sequence), 49 | decode(JSON) 50 | ); 51 | assert("i_" ++ _, _JSON) -> 52 | ?assert(true). 53 | 54 | % FIXME: 55 | % The CI if failing due to this: 56 | % > test/euneus_decoder_SUITE.erl 57 | % > Line 60 Column 1: Function stream_continue_test/1 has no local return 58 | % > Line 64 Column 10: The created fun has no local return 59 | % > Line 64 Column 77: The call euneus_decoder:stream_continue( 60 | % <<49>>, 61 | % State1::json:continuation_state() 62 | % ) 63 | % contains an opaque term as 2nd argument when terms of different types 64 | % are expected in these positions 65 | % 66 | % stream_start_test(Config) when is_list(Config) -> 67 | % [ 68 | % ?assertMatch({continue, _}, euneus_decoder:stream_start(<<"{\"foo\":">>, #{})), 69 | % ?assertEqual({end_of_input, <<"foo">>}, euneus_decoder:stream_start(<<"\"foo\"">>, #{})) 70 | % ]. 71 | % 72 | % stream_continue_test(Config) when is_list(Config) -> 73 | % {continue, State1} = euneus_decoder:stream_start(<<"{\"foo\":">>, #{}), 74 | % {continue, State2} = euneus_decoder:stream_start(<<"123">>, #{}), 75 | % [ 76 | % ?assertMatch({continue, _}, euneus_decoder:stream_continue(<<"1">>, State1)), 77 | % ?assertEqual( 78 | % {end_of_input, #{<<"foo">> => 1}}, euneus_decoder:stream_continue(<<"1}">>, State1) 79 | % ), 80 | % ?assertError(unexpected_end, euneus_decoder:stream_continue(end_of_input, State1)), 81 | % ?assertEqual({end_of_input, 123}, euneus_decoder:stream_continue(<<>>, State2)) 82 | % ]. 83 | 84 | codecs_test(Config) when is_list(Config) -> 85 | [ 86 | ?assertEqual([], decode(<<"[]">>, #{codecs => []})), 87 | ?assertEqual([null], decode(<<"[null]">>, #{codecs => [fun(_) -> next end]})), 88 | ?assertEqual( 89 | <<"foo">>, 90 | decode(<<"\"foo\"">>, #{ 91 | codecs => [ 92 | timestamp, 93 | datetime, 94 | ipv4, 95 | ipv6, 96 | pid, 97 | port, 98 | reference, 99 | fun(_) -> next end, 100 | copy 101 | ] 102 | }) 103 | ) 104 | ]. 105 | 106 | copy_codec_test(Config) when is_list(Config) -> 107 | ?assertEqual(<<"foo">>, decode(<<"\"foo\"">>, #{codecs => [copy]})). 108 | 109 | timestamp_codec_test(Config) when is_list(Config) -> 110 | ?assertEqual({0, 0, 0}, decode(<<"\"1970-01-01T00:00:00.000Z\"">>, #{codecs => [timestamp]})). 111 | 112 | datetime_codec_test(Config) when is_list(Config) -> 113 | ?assertEqual( 114 | {{1970, 1, 1}, {0, 0, 0}}, decode(<<"\"1970-01-01T00:00:00Z\"">>, #{codecs => [datetime]}) 115 | ). 116 | 117 | ipv4_codec_test(Config) when is_list(Config) -> 118 | [ 119 | ?assertEqual({0, 0, 0, 0}, decode(<<"\"0.0.0.0\"">>, #{codecs => [ipv4]})), 120 | ?assertEqual(<<"0.0.0.256">>, decode(<<"\"0.0.0.256\"">>, #{codecs => [ipv4]})), 121 | ?assertEqual(<<"00.256">>, decode(<<"\"00.256\"">>, #{codecs => [ipv4]})), 122 | ?assertEqual(<<"0.256">>, decode(<<"\"0.256\"">>, #{codecs => [ipv4]})) 123 | ]. 124 | 125 | ipv6_codec_test(Config) when is_list(Config) -> 126 | [ 127 | ?assertEqual({0, 0, 0, 0, 0, 0, 0, 0}, decode(<<"\"::\"">>, #{codecs => [ipv6]})), 128 | ?assertEqual({0, 0, 0, 0, 0, 0, 0, 1}, decode(<<"\"::1\"">>, #{codecs => [ipv6]})), 129 | ?assertEqual( 130 | {0, 0, 0, 0, 0, 0, (192 bsl 8) bor 168, (42 bsl 8) bor 2}, 131 | decode(<<"\"::192.168.42.2\"">>, #{codecs => [ipv6]}) 132 | ), 133 | ?assertEqual( 134 | {0, 0, 0, 0, 0, 16#FFFF, (192 bsl 8) bor 168, (42 bsl 8) bor 2}, 135 | decode(<<"\"::ffff:192.168.42.2\"">>, #{codecs => [ipv6]}) 136 | ), 137 | ?assertEqual( 138 | {16#3ffe, 16#b80, 16#1f8d, 16#2, 16#204, 16#acff, 16#fe17, 16#bf38}, 139 | decode(<<"\"3ffe:b80:1f8d:2:204:acff:fe17:bf38\"">>, #{codecs => [ipv6]}) 140 | ), 141 | ?assertEqual( 142 | {16#fe80, 0, 0, 0, 16#204, 16#acff, 16#fe17, 16#bf38}, 143 | decode(<<"\"fe80::204:acff:fe17:bf38\"">>, #{codecs => [ipv6]}) 144 | ), 145 | ?assertEqual(<<"::x">>, decode(<<"\"::x\"">>, #{codecs => [ipv6]})) 146 | ]. 147 | 148 | pid_codec_test(Config) when is_list(Config) -> 149 | [ 150 | ?assertEqual(list_to_pid("<0.92.0>"), decode(<<"\"<0.92.0>\"">>, #{codecs => [pid]})), 151 | ?assertEqual(<<">, decode(<<"\">, #{codecs => [pid]})) 152 | ]. 153 | 154 | port_codec_test(Config) when is_list(Config) -> 155 | [ 156 | ?assertEqual( 157 | list_to_port("#Port<0.1>"), decode(<<"\"#Port<0.1>\"">>, #{codecs => [port]}) 158 | ), 159 | ?assertEqual(<<"#Port>, decode(<<"\"#Port>, #{codecs => [port]})) 160 | ]. 161 | 162 | reference_codec_test(Config) when is_list(Config) -> 163 | [ 164 | ?assertEqual( 165 | list_to_ref("#Ref<0.314572725.1088159747.110918>"), 166 | decode(<<"\"#Ref<0.314572725.1088159747.110918>\"">>, #{codecs => [reference]}) 167 | ), 168 | ?assertEqual( 169 | <<"#Ref>, 170 | decode(<<"\"#Ref>, #{codecs => [reference]}) 171 | ) 172 | ]. 173 | 174 | null_test(Config) when is_list(Config) -> 175 | [ 176 | ?assertEqual(null, decode(<<"null">>)), 177 | ?assertEqual(foo, decode(<<"null">>, #{null => foo})) 178 | ]. 179 | 180 | binary_to_float_test(Config) when is_list(Config) -> 181 | [ 182 | ?assertEqual(0.0001, decode(<<"0.0001">>)), 183 | ?assertEqual(foo, decode(<<"0.0001">>, #{binary_to_float => fun(_) -> foo end})) 184 | ]. 185 | 186 | binary_to_integer_test(Config) when is_list(Config) -> 187 | [ 188 | ?assertEqual(0, decode(<<"0">>)), 189 | ?assertEqual(foo, decode(<<"0">>, #{binary_to_integer => fun(_) -> foo end})) 190 | ]. 191 | 192 | array_start_test(Config) when is_list(Config) -> 193 | [ 194 | ?assertEqual([], decode(<<"[]">>)), 195 | ?assertEqual([foo], decode(<<"[]">>, #{array_start => fun(_) -> [foo] end})) 196 | ]. 197 | 198 | array_push_test(Config) when is_list(Config) -> 199 | ?assertEqual([foo], decode(<<"[null]">>, #{array_push => fun(_, _) -> [foo] end})). 200 | 201 | array_finish_test(Config) when is_list(Config) -> 202 | [ 203 | ?assertEqual([0, 1, 2], decode(<<"[0,1,2]">>)), 204 | ?assertEqual([2, 1, 0], decode(<<"[0,1,2]">>, #{array_finish => reversed})), 205 | ?assertEqual([], decode(<<"[0,1,2]">>, #{array_finish => fun(_, _) -> {[], []} end})) 206 | ]. 207 | 208 | object_push_test(Config) when is_list(Config) -> 209 | ?assertEqual(#{}, decode(<<"{\"foo\":\"bar\"}">>, #{object_push => fun(_, _, _) -> [] end})). 210 | 211 | object_keys_test(Config) when is_list(Config) -> 212 | [ 213 | ?assertEqual(#{<<"foo">> => <<"bar">>}, decode(<<"{\"foo\":\"bar\"}">>)), 214 | ?assertEqual( 215 | #{<<"foo">> => <<"bar">>}, decode(<<"{\"foo\":\"bar\"}">>, #{object_keys => copy}) 216 | ), 217 | ?assertEqual( 218 | #{foo => <<"bar">>}, decode(<<"{\"foo\":\"bar\"}">>, #{object_keys => atom}) 219 | ), 220 | ?assertEqual( 221 | #{foo => <<"bar">>}, decode(<<"{\"foo\":\"bar\"}">>, #{object_keys => existing_atom}) 222 | ), 223 | ?assertEqual( 224 | #{bar => <<"bar">>}, 225 | decode(<<"{\"foo\":\"bar\"}">>, #{object_keys => fun(_) -> bar end}) 226 | ) 227 | ]. 228 | 229 | object_finish_test(Config) when is_list(Config) -> 230 | [ 231 | ?assertEqual(#{}, decode(<<"{}">>)), 232 | ?assertEqual( 233 | [{<<"foo">>, <<"bar">>}, {<<"bar">>, <<"baz">>}], 234 | decode(<<"{\"foo\":\"bar\",\"bar\":\"baz\"}">>, #{object_finish => proplist}) 235 | ), 236 | ?assertEqual( 237 | [{<<"bar">>, <<"baz">>}, {<<"foo">>, <<"bar">>}], 238 | decode(<<"{\"foo\":\"bar\",\"bar\":\"baz\"}">>, #{object_finish => reversed_proplist}) 239 | ), 240 | ?assertEqual([], decode(<<"{}">>, #{object_finish => fun(_, _) -> {[], []} end})) 241 | ]. 242 | 243 | %% -------------------------------------------------------------------- 244 | %% Test support 245 | %% -------------------------------------------------------------------- 246 | 247 | decode(Bin) -> 248 | euneus:decode(Bin). 249 | 250 | decode(Bin, Opts) -> 251 | euneus:decode(Bin, Opts). 252 | -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_number_double_huge_neg_exp.json: -------------------------------------------------------------------------------- 1 | [123.456e-789] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_number_huge_exp.json: -------------------------------------------------------------------------------- 1 | [0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_number_neg_int_huge_exp.json: -------------------------------------------------------------------------------- 1 | [-1e+9999] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_number_pos_double_huge_exp.json: -------------------------------------------------------------------------------- 1 | [1.5e+9999] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_number_real_neg_overflow.json: -------------------------------------------------------------------------------- 1 | [-123123e100000] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_number_real_pos_overflow.json: -------------------------------------------------------------------------------- 1 | [123123e100000] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_number_real_underflow.json: -------------------------------------------------------------------------------- 1 | [123e-10000000] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_number_too_big_neg_int.json: -------------------------------------------------------------------------------- 1 | [-123123123123123123123123123123] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_number_too_big_pos_int.json: -------------------------------------------------------------------------------- 1 | [100000000000000000000] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_number_very_big_negative_int.json: -------------------------------------------------------------------------------- 1 | [-237462374673276894279832749832423479823246327846] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_object_key_lone_2nd_surrogate.json: -------------------------------------------------------------------------------- 1 | {"\uDFAA":0} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_1st_surrogate_but_2nd_missing.json: -------------------------------------------------------------------------------- 1 | ["\uDADA"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_1st_valid_surrogate_2nd_invalid.json: -------------------------------------------------------------------------------- 1 | ["\uD888\u1234"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_UTF-16LE_with_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/i_string_UTF-16LE_with_BOM.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_UTF-8_invalid_sequence.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/i_string_UTF-8_invalid_sequence.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_UTF8_surrogate_U+D800.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/i_string_UTF8_surrogate_U+D800.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_incomplete_surrogate_and_escape_valid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\n"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_incomplete_surrogate_pair.json: -------------------------------------------------------------------------------- 1 | ["\uDd1ea"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_incomplete_surrogates_escape_valid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\n"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_invalid_lonely_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\ud800"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_invalid_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\ud800abc"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_invalid_utf-8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/i_string_invalid_utf-8.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_inverted_surrogates_U+1D11E.json: -------------------------------------------------------------------------------- 1 | ["\uDd1e\uD834"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_iso_latin_1.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/i_string_iso_latin_1.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_lone_second_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\uDFAA"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_lone_utf8_continuation_byte.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/i_string_lone_utf8_continuation_byte.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_not_in_unicode_range.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/i_string_not_in_unicode_range.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_overlong_sequence_2_bytes.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/i_string_overlong_sequence_2_bytes.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_overlong_sequence_6_bytes.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/i_string_overlong_sequence_6_bytes.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_overlong_sequence_6_bytes_null.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/i_string_overlong_sequence_6_bytes_null.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_truncated-utf-8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/i_string_truncated-utf-8.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_utf16BE_no_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/i_string_utf16BE_no_BOM.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_string_utf16LE_no_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/i_string_utf16LE_no_BOM.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_structure_500_nested_arrays.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/i_structure_UTF-8_BOM_empty_object.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_1_true_without_comma.json: -------------------------------------------------------------------------------- 1 | [1 true] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_a_invalid_utf8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/n_array_a_invalid_utf8.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_colon_instead_of_comma.json: -------------------------------------------------------------------------------- 1 | ["": 1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_comma_after_close.json: -------------------------------------------------------------------------------- 1 | [""], -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_comma_and_number.json: -------------------------------------------------------------------------------- 1 | [,1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_double_comma.json: -------------------------------------------------------------------------------- 1 | [1,,2] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_double_extra_comma.json: -------------------------------------------------------------------------------- 1 | ["x",,] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_extra_close.json: -------------------------------------------------------------------------------- 1 | ["x"]] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_extra_comma.json: -------------------------------------------------------------------------------- 1 | ["",] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_incomplete.json: -------------------------------------------------------------------------------- 1 | ["x" -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_incomplete_invalid_value.json: -------------------------------------------------------------------------------- 1 | [x -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_inner_array_no_comma.json: -------------------------------------------------------------------------------- 1 | [3[4]] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_invalid_utf8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/n_array_invalid_utf8.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_items_separated_by_semicolon.json: -------------------------------------------------------------------------------- 1 | [1:2] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_just_comma.json: -------------------------------------------------------------------------------- 1 | [,] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_just_minus.json: -------------------------------------------------------------------------------- 1 | [-] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_missing_value.json: -------------------------------------------------------------------------------- 1 | [ , ""] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_newlines_unclosed.json: -------------------------------------------------------------------------------- 1 | ["a", 2 | 4 3 | ,1, -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_number_and_comma.json: -------------------------------------------------------------------------------- 1 | [1,] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_number_and_several_commas.json: -------------------------------------------------------------------------------- 1 | [1,,] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_spaces_vertical_tab_formfeed.json: -------------------------------------------------------------------------------- 1 | [" a"\f] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_star_inside.json: -------------------------------------------------------------------------------- 1 | [*] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_unclosed.json: -------------------------------------------------------------------------------- 1 | ["" -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_unclosed_trailing_comma.json: -------------------------------------------------------------------------------- 1 | [1, -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_unclosed_with_new_lines.json: -------------------------------------------------------------------------------- 1 | [1, 2 | 1 3 | ,1 -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_array_unclosed_with_object_inside.json: -------------------------------------------------------------------------------- 1 | [{} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_incomplete_false.json: -------------------------------------------------------------------------------- 1 | [fals] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_incomplete_null.json: -------------------------------------------------------------------------------- 1 | [nul] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_incomplete_true.json: -------------------------------------------------------------------------------- 1 | [tru] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_multidigit_number_then_00.json: -------------------------------------------------------------------------------- 1 | 123 -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_++.json: -------------------------------------------------------------------------------- 1 | [++1234] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_+1.json: -------------------------------------------------------------------------------- 1 | [+1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_+Inf.json: -------------------------------------------------------------------------------- 1 | [+Inf] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_-01.json: -------------------------------------------------------------------------------- 1 | [-01] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_-1.0..json: -------------------------------------------------------------------------------- 1 | [-1.0.] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_-2..json: -------------------------------------------------------------------------------- 1 | [-2.] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_-NaN.json: -------------------------------------------------------------------------------- 1 | [-NaN] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_.-1.json: -------------------------------------------------------------------------------- 1 | [.-1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_.2e-3.json: -------------------------------------------------------------------------------- 1 | [.2e-3] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_0.1.2.json: -------------------------------------------------------------------------------- 1 | [0.1.2] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_0.3e+.json: -------------------------------------------------------------------------------- 1 | [0.3e+] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_0.3e.json: -------------------------------------------------------------------------------- 1 | [0.3e] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_0.e1.json: -------------------------------------------------------------------------------- 1 | [0.e1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_0_capital_E+.json: -------------------------------------------------------------------------------- 1 | [0E+] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_0_capital_E.json: -------------------------------------------------------------------------------- 1 | [0E] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_0e+.json: -------------------------------------------------------------------------------- 1 | [0e+] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_0e.json: -------------------------------------------------------------------------------- 1 | [0e] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_1.0e+.json: -------------------------------------------------------------------------------- 1 | [1.0e+] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_1.0e-.json: -------------------------------------------------------------------------------- 1 | [1.0e-] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_1.0e.json: -------------------------------------------------------------------------------- 1 | [1.0e] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_1_000.json: -------------------------------------------------------------------------------- 1 | [1 000.0] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_1eE2.json: -------------------------------------------------------------------------------- 1 | [1eE2] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_2.e+3.json: -------------------------------------------------------------------------------- 1 | [2.e+3] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_2.e-3.json: -------------------------------------------------------------------------------- 1 | [2.e-3] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_2.e3.json: -------------------------------------------------------------------------------- 1 | [2.e3] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_9.e+.json: -------------------------------------------------------------------------------- 1 | [9.e+] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_Inf.json: -------------------------------------------------------------------------------- 1 | [Inf] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_NaN.json: -------------------------------------------------------------------------------- 1 | [NaN] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_U+FF11_fullwidth_digit_one.json: -------------------------------------------------------------------------------- 1 | [1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_expression.json: -------------------------------------------------------------------------------- 1 | [1+2] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_hex_1_digit.json: -------------------------------------------------------------------------------- 1 | [0x1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_hex_2_digits.json: -------------------------------------------------------------------------------- 1 | [0x42] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_infinity.json: -------------------------------------------------------------------------------- 1 | [Infinity] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_invalid+-.json: -------------------------------------------------------------------------------- 1 | [0e+-1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_invalid-negative-real.json: -------------------------------------------------------------------------------- 1 | [-123.123foo] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_invalid-utf-8-in-bigger-int.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/n_number_invalid-utf-8-in-bigger-int.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_invalid-utf-8-in-exponent.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/n_number_invalid-utf-8-in-exponent.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_invalid-utf-8-in-int.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/n_number_invalid-utf-8-in-int.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_minus_infinity.json: -------------------------------------------------------------------------------- 1 | [-Infinity] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_minus_sign_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | [-foo] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_minus_space_1.json: -------------------------------------------------------------------------------- 1 | [- 1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_neg_int_starting_with_zero.json: -------------------------------------------------------------------------------- 1 | [-012] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_neg_real_without_int_part.json: -------------------------------------------------------------------------------- 1 | [-.123] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_neg_with_garbage_at_end.json: -------------------------------------------------------------------------------- 1 | [-1x] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_real_garbage_after_e.json: -------------------------------------------------------------------------------- 1 | [1ea] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_real_with_invalid_utf8_after_e.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/n_number_real_with_invalid_utf8_after_e.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_real_without_fractional_part.json: -------------------------------------------------------------------------------- 1 | [1.] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_starting_with_dot.json: -------------------------------------------------------------------------------- 1 | [.123] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_with_alpha.json: -------------------------------------------------------------------------------- 1 | [1.2a-3] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_with_alpha_char.json: -------------------------------------------------------------------------------- 1 | [1.8011670033376514H-308] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_number_with_leading_zero.json: -------------------------------------------------------------------------------- 1 | [012] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_bad_value.json: -------------------------------------------------------------------------------- 1 | ["x", truth] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_bracket_key.json: -------------------------------------------------------------------------------- 1 | {[: "x"} 2 | -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_comma_instead_of_colon.json: -------------------------------------------------------------------------------- 1 | {"x", null} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_double_colon.json: -------------------------------------------------------------------------------- 1 | {"x"::"b"} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_emoji.json: -------------------------------------------------------------------------------- 1 | {🇨🇭} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_garbage_at_end.json: -------------------------------------------------------------------------------- 1 | {"a":"a" 123} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_key_with_single_quotes.json: -------------------------------------------------------------------------------- 1 | {key: 'value'} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_lone_continuation_byte_in_key_and_trailing_comma.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/n_object_lone_continuation_byte_in_key_and_trailing_comma.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_missing_colon.json: -------------------------------------------------------------------------------- 1 | {"a" b} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_missing_key.json: -------------------------------------------------------------------------------- 1 | {:"b"} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_missing_semicolon.json: -------------------------------------------------------------------------------- 1 | {"a" "b"} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_missing_value.json: -------------------------------------------------------------------------------- 1 | {"a": -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_no-colon.json: -------------------------------------------------------------------------------- 1 | {"a" -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_non_string_key.json: -------------------------------------------------------------------------------- 1 | {1:1} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_non_string_key_but_huge_number_instead.json: -------------------------------------------------------------------------------- 1 | {9999E9999:1} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_repeated_null_null.json: -------------------------------------------------------------------------------- 1 | {null:null,null:null} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_several_trailing_commas.json: -------------------------------------------------------------------------------- 1 | {"id":0,,,,,} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_single_quote.json: -------------------------------------------------------------------------------- 1 | {'a':0} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_trailing_comma.json: -------------------------------------------------------------------------------- 1 | {"id":0,} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_trailing_comment.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/**/ -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_trailing_comment_open.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/**// -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_trailing_comment_slash_open.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}// -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_trailing_comment_slash_open_incomplete.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/ -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_two_commas_in_a_row.json: -------------------------------------------------------------------------------- 1 | {"a":"b",,"c":"d"} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_unquoted_key.json: -------------------------------------------------------------------------------- 1 | {a: "b"} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_unterminated-value.json: -------------------------------------------------------------------------------- 1 | {"a":"a -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_with_single_string.json: -------------------------------------------------------------------------------- 1 | { "foo" : "bar", "a" } -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_object_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}# -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_single_space.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_1_surrogate_then_escape.json: -------------------------------------------------------------------------------- 1 | ["\uD800\"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_1_surrogate_then_escape_u.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_1_surrogate_then_escape_u1.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u1"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_1_surrogate_then_escape_u1x.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u1x"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_accentuated_char_no_quotes.json: -------------------------------------------------------------------------------- 1 | [é] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_backslash_00.json: -------------------------------------------------------------------------------- 1 | ["\"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_escape_x.json: -------------------------------------------------------------------------------- 1 | ["\x00"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_escaped_backslash_bad.json: -------------------------------------------------------------------------------- 1 | ["\\\"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_escaped_ctrl_char_tab.json: -------------------------------------------------------------------------------- 1 | ["\ "] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_escaped_emoji.json: -------------------------------------------------------------------------------- 1 | ["\🌀"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_incomplete_escape.json: -------------------------------------------------------------------------------- 1 | ["\"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_incomplete_escaped_character.json: -------------------------------------------------------------------------------- 1 | ["\u00A"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_incomplete_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\uD834\uDd"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_incomplete_surrogate_escape_invalid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\x"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_invalid-utf-8-in-escape.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/n_string_invalid-utf-8-in-escape.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_invalid_backslash_esc.json: -------------------------------------------------------------------------------- 1 | ["\a"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_invalid_unicode_escape.json: -------------------------------------------------------------------------------- 1 | ["\uqqqq"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_invalid_utf8_after_escape.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/n_string_invalid_utf8_after_escape.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_leading_uescaped_thinspace.json: -------------------------------------------------------------------------------- 1 | [\u0020"asd"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_no_quotes_with_bad_escape.json: -------------------------------------------------------------------------------- 1 | [\n] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_single_doublequote.json: -------------------------------------------------------------------------------- 1 | " -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_single_quote.json: -------------------------------------------------------------------------------- 1 | ['single quote'] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_single_string_no_double_quotes.json: -------------------------------------------------------------------------------- 1 | abc -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_start_escape_unclosed.json: -------------------------------------------------------------------------------- 1 | ["\ -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_unescaped_ctrl_char.json: -------------------------------------------------------------------------------- 1 | ["aa"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_unescaped_newline.json: -------------------------------------------------------------------------------- 1 | ["new 2 | line"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_unescaped_tab.json: -------------------------------------------------------------------------------- 1 | [" "] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_unicode_CapitalU.json: -------------------------------------------------------------------------------- 1 | "\UA66D" -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_string_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | ""x -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_U+2060_word_joined.json: -------------------------------------------------------------------------------- 1 | [⁠] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_UTF8_BOM_no_data.json: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_angle_bracket_..json: -------------------------------------------------------------------------------- 1 | <.> -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_angle_bracket_null.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_array_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | [1]x -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_array_with_extra_array_close.json: -------------------------------------------------------------------------------- 1 | [1]] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_array_with_unclosed_string.json: -------------------------------------------------------------------------------- 1 | ["asd] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_ascii-unicode-identifier.json: -------------------------------------------------------------------------------- 1 | aå -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_capitalized_True.json: -------------------------------------------------------------------------------- 1 | [True] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_close_unopened_array.json: -------------------------------------------------------------------------------- 1 | 1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_comma_instead_of_closing_brace.json: -------------------------------------------------------------------------------- 1 | {"x": true, -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_double_array.json: -------------------------------------------------------------------------------- 1 | [][] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_end_array.json: -------------------------------------------------------------------------------- 1 | ] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_incomplete_UTF8_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/n_structure_incomplete_UTF8_BOM.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_lone-invalid-utf-8.json: -------------------------------------------------------------------------------- 1 | � -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_lone-open-bracket.json: -------------------------------------------------------------------------------- 1 | [ -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_no_data.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_decoder_SUITE_data/n_structure_no_data.json -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_null-byte-outside-string.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_number_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | 2@ -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_object_followed_by_closing_object.json: -------------------------------------------------------------------------------- 1 | {}} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_object_unclosed_no_value.json: -------------------------------------------------------------------------------- 1 | {"": -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_object_with_comment.json: -------------------------------------------------------------------------------- 1 | {"a":/*comment*/"b"} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_object_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | {"a": true} "x" -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_open_array_apostrophe.json: -------------------------------------------------------------------------------- 1 | [' -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_open_array_comma.json: -------------------------------------------------------------------------------- 1 | [, -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_open_array_open_object.json: -------------------------------------------------------------------------------- 1 | [{ -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_open_array_open_string.json: -------------------------------------------------------------------------------- 1 | ["a -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_open_array_string.json: -------------------------------------------------------------------------------- 1 | ["a" -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_open_object.json: -------------------------------------------------------------------------------- 1 | { -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_open_object_close_array.json: -------------------------------------------------------------------------------- 1 | {] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_open_object_comma.json: -------------------------------------------------------------------------------- 1 | {, -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_open_object_open_array.json: -------------------------------------------------------------------------------- 1 | {[ -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_open_object_open_string.json: -------------------------------------------------------------------------------- 1 | {"a -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_open_object_string_with_apostrophes.json: -------------------------------------------------------------------------------- 1 | {'a' -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_open_open.json: -------------------------------------------------------------------------------- 1 | ["\{["\{["\{["\{ -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_single_eacute.json: -------------------------------------------------------------------------------- 1 | � -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_single_star.json: -------------------------------------------------------------------------------- 1 | * -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_trailing_#.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}#{} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_uescaped_LF_before_string.json: -------------------------------------------------------------------------------- 1 | [\u000A""] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_unclosed_array.json: -------------------------------------------------------------------------------- 1 | [1 -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_unclosed_array_partial_null.json: -------------------------------------------------------------------------------- 1 | [ false, nul -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_unclosed_array_unfinished_false.json: -------------------------------------------------------------------------------- 1 | [ true, fals -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_unclosed_array_unfinished_true.json: -------------------------------------------------------------------------------- 1 | [ false, tru -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_unclosed_object.json: -------------------------------------------------------------------------------- 1 | {"asd":"asd" -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_unicode-identifier.json: -------------------------------------------------------------------------------- 1 | å -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_whitespace_U+2060_word_joiner.json: -------------------------------------------------------------------------------- 1 | [⁠] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/n_structure_whitespace_formfeed.json: -------------------------------------------------------------------------------- 1 | [ ] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_array_arraysWithSpaces.json: -------------------------------------------------------------------------------- 1 | [[] ] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_array_empty-string.json: -------------------------------------------------------------------------------- 1 | [""] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_array_empty.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_array_ending_with_newline.json: -------------------------------------------------------------------------------- 1 | ["a"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_array_false.json: -------------------------------------------------------------------------------- 1 | [false] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_array_heterogeneous.json: -------------------------------------------------------------------------------- 1 | [null, 1, "1", {}] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_array_null.json: -------------------------------------------------------------------------------- 1 | [null] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_array_with_1_and_newline.json: -------------------------------------------------------------------------------- 1 | [1 2 | ] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_array_with_leading_space.json: -------------------------------------------------------------------------------- 1 | [1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_array_with_several_null.json: -------------------------------------------------------------------------------- 1 | [1,null,null,null,2] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_array_with_trailing_space.json: -------------------------------------------------------------------------------- 1 | [2] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number.json: -------------------------------------------------------------------------------- 1 | [123e65] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_0e+1.json: -------------------------------------------------------------------------------- 1 | [0e+1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_0e1.json: -------------------------------------------------------------------------------- 1 | [0e1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_after_space.json: -------------------------------------------------------------------------------- 1 | [ 4] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_double_close_to_zero.json: -------------------------------------------------------------------------------- 1 | [-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] 2 | -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_int_with_exp.json: -------------------------------------------------------------------------------- 1 | [20e1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_minus_zero.json: -------------------------------------------------------------------------------- 1 | [-0] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_negative_int.json: -------------------------------------------------------------------------------- 1 | [-123] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_negative_one.json: -------------------------------------------------------------------------------- 1 | [-1] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_negative_zero.json: -------------------------------------------------------------------------------- 1 | [-0] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_real_capital_e.json: -------------------------------------------------------------------------------- 1 | [1E22] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_real_capital_e_neg_exp.json: -------------------------------------------------------------------------------- 1 | [1E-2] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_real_capital_e_pos_exp.json: -------------------------------------------------------------------------------- 1 | [1E+2] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_real_exponent.json: -------------------------------------------------------------------------------- 1 | [123e45] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_real_fraction_exponent.json: -------------------------------------------------------------------------------- 1 | [123.456e78] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_real_neg_exp.json: -------------------------------------------------------------------------------- 1 | [1e-2] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_real_pos_exponent.json: -------------------------------------------------------------------------------- 1 | [1e+2] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_simple_int.json: -------------------------------------------------------------------------------- 1 | [123] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_number_simple_real.json: -------------------------------------------------------------------------------- 1 | [123.456789] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_object.json: -------------------------------------------------------------------------------- 1 | {"asd":"sdf", "dfg":"fgh"} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_object_basic.json: -------------------------------------------------------------------------------- 1 | {"asd":"sdf"} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_object_duplicated_key.json: -------------------------------------------------------------------------------- 1 | {"a":"b","a":"c"} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_object_duplicated_key_and_value.json: -------------------------------------------------------------------------------- 1 | {"a":"b","a":"b"} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_object_empty.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_object_empty_key.json: -------------------------------------------------------------------------------- 1 | {"":0} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_object_escaped_null_in_key.json: -------------------------------------------------------------------------------- 1 | {"foo\u0000bar": 42} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_object_extreme_numbers.json: -------------------------------------------------------------------------------- 1 | { "min": -1.0e+28, "max": 1.0e+28 } -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_object_long_strings.json: -------------------------------------------------------------------------------- 1 | {"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_object_simple.json: -------------------------------------------------------------------------------- 1 | {"a":[]} -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_object_string_unicode.json: -------------------------------------------------------------------------------- 1 | {"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_object_with_newlines.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": "b" 3 | } -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_1_2_3_bytes_UTF-8_sequences.json: -------------------------------------------------------------------------------- 1 | ["\u0060\u012a\u12AB"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_accepted_surrogate_pair.json: -------------------------------------------------------------------------------- 1 | ["\uD801\udc37"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_accepted_surrogate_pairs.json: -------------------------------------------------------------------------------- 1 | ["\ud83d\ude39\ud83d\udc8d"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_allowed_escapes.json: -------------------------------------------------------------------------------- 1 | ["\"\\\/\b\f\n\r\t"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_backslash_and_u_escaped_zero.json: -------------------------------------------------------------------------------- 1 | ["\\u0000"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_backslash_doublequotes.json: -------------------------------------------------------------------------------- 1 | ["\""] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_comments.json: -------------------------------------------------------------------------------- 1 | ["a/*b*/c/*d//e"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_double_escape_a.json: -------------------------------------------------------------------------------- 1 | ["\\a"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_double_escape_n.json: -------------------------------------------------------------------------------- 1 | ["\\n"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_escaped_control_character.json: -------------------------------------------------------------------------------- 1 | ["\u0012"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_escaped_noncharacter.json: -------------------------------------------------------------------------------- 1 | ["\uFFFF"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_in_array.json: -------------------------------------------------------------------------------- 1 | ["asd"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_in_array_with_leading_space.json: -------------------------------------------------------------------------------- 1 | [ "asd"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_last_surrogates_1_and_2.json: -------------------------------------------------------------------------------- 1 | ["\uDBFF\uDFFF"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_nbsp_uescaped.json: -------------------------------------------------------------------------------- 1 | ["new\u00A0line"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_nonCharacterInUTF-8_U+10FFFF.json: -------------------------------------------------------------------------------- 1 | ["􏿿"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_nonCharacterInUTF-8_U+FFFF.json: -------------------------------------------------------------------------------- 1 | ["￿"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_null_escape.json: -------------------------------------------------------------------------------- 1 | ["\u0000"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_one-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u002c"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_pi.json: -------------------------------------------------------------------------------- 1 | ["π"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_reservedCharacterInUTF-8_U+1BFFF.json: -------------------------------------------------------------------------------- 1 | ["𛿿"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_simple_ascii.json: -------------------------------------------------------------------------------- 1 | ["asd "] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_space.json: -------------------------------------------------------------------------------- 1 | " " -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json: -------------------------------------------------------------------------------- 1 | ["\uD834\uDd1e"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_three-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u0821"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_two-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u0123"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_u+2028_line_sep.json: -------------------------------------------------------------------------------- 1 | ["
"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_u+2029_par_sep.json: -------------------------------------------------------------------------------- 1 | ["
"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_uEscape.json: -------------------------------------------------------------------------------- 1 | ["\u0061\u30af\u30EA\u30b9"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_uescaped_newline.json: -------------------------------------------------------------------------------- 1 | ["new\u000Aline"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_unescaped_char_delete.json: -------------------------------------------------------------------------------- 1 | [""] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_unicode.json: -------------------------------------------------------------------------------- 1 | ["\uA66D"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_unicodeEscapedBackslash.json: -------------------------------------------------------------------------------- 1 | ["\u005C"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_unicode_2.json: -------------------------------------------------------------------------------- 1 | ["⍂㈴⍂"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_unicode_U+10FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uDBFF\uDFFE"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_unicode_U+1FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uD83F\uDFFE"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json: -------------------------------------------------------------------------------- 1 | ["\u200B"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_unicode_U+2064_invisible_plus.json: -------------------------------------------------------------------------------- 1 | ["\u2064"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_unicode_U+FDD0_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uFDD0"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_unicode_U+FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uFFFE"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_unicode_escaped_double_quote.json: -------------------------------------------------------------------------------- 1 | ["\u0022"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_utf8.json: -------------------------------------------------------------------------------- 1 | ["€𝄞"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_string_with_del_character.json: -------------------------------------------------------------------------------- 1 | ["aa"] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_structure_lonely_false.json: -------------------------------------------------------------------------------- 1 | false -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_structure_lonely_int.json: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_structure_lonely_negative_real.json: -------------------------------------------------------------------------------- 1 | -0.1 -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_structure_lonely_null.json: -------------------------------------------------------------------------------- 1 | null -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_structure_lonely_string.json: -------------------------------------------------------------------------------- 1 | "asd" -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_structure_lonely_true.json: -------------------------------------------------------------------------------- 1 | true -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_structure_string_empty.json: -------------------------------------------------------------------------------- 1 | "" -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_structure_trailing_newline.json: -------------------------------------------------------------------------------- 1 | ["a"] 2 | -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_structure_true_in_array.json: -------------------------------------------------------------------------------- 1 | [true] -------------------------------------------------------------------------------- /test/euneus_decoder_SUITE_data/y_structure_whitespace_array.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE.erl: -------------------------------------------------------------------------------- 1 | -module(euneus_encoder_SUITE). 2 | -behaviour(ct_suite). 3 | -include_lib("stdlib/include/assert.hrl"). 4 | -compile([export_all, nowarn_export_all]). 5 | 6 | % 7 | 8 | -elvis([{elvis_style, dont_repeat_yourself, disable}]). 9 | 10 | %% -------------------------------------------------------------------- 11 | %% Behaviour (ct_suite) callbacks 12 | %% -------------------------------------------------------------------- 13 | 14 | all() -> 15 | [ 16 | Fun 17 | || {Fun, 1} <- ?MODULE:module_info(exports), 18 | re:run(atom_to_binary(Fun), <<".*_test$">>) =/= nomatch 19 | ]. 20 | 21 | %% -------------------------------------------------------------------- 22 | %% Tests 23 | %% -------------------------------------------------------------------- 24 | 25 | encode_test(Config) -> 26 | DataDir = proplists:get_value(data_dir, Config), 27 | {ok, Files} = file:list_dir(DataDir), 28 | lists:foreach( 29 | fun(Filename) -> 30 | case string:find(Filename, "invalid") of 31 | nomatch -> 32 | AbsFilename = filename:join(DataDir, Filename), 33 | {ok, JSON} = file:read_file(AbsFilename), 34 | Term = euneus:decode(JSON), 35 | ?assertNotException( 36 | error, 37 | Reason when 38 | Reason =:= unexpected_end; 39 | (is_tuple(Reason) andalso element(1, Reason) =:= invalid_byte), 40 | encode(Term) 41 | ); 42 | _Invalid -> 43 | ?assert(true) 44 | end 45 | end, 46 | Files 47 | ). 48 | 49 | codecs_test(Config) when is_list(Config) -> 50 | [ 51 | ?assertEqual(<<"\"foo\"">>, encode(foo, #{codecs => []})), 52 | ?assertEqual( 53 | <<"\"foo\"">>, 54 | encode({foo}, #{ 55 | codecs => [ 56 | timestamp, 57 | datetime, 58 | ipv4, 59 | ipv6, 60 | {records, #{}}, 61 | fun({foo}) -> {halt, foo} end 62 | ] 63 | }) 64 | ) 65 | ]. 66 | 67 | codec_callback_test(Config) when is_list(Config) -> 68 | ?assertEqual( 69 | <<"[\"foo\"]">>, 70 | encode({foo}, #{ 71 | codecs => [tuple_to_list], 72 | codec_callback => fun(tuple_to_list, Tuple) -> 73 | {halt, erlang:tuple_to_list(Tuple)} 74 | end 75 | }) 76 | ). 77 | 78 | timestamp_codec_test(Config) when is_list(Config) -> 79 | ?assertEqual(<<"\"1970-01-01T00:00:00.000Z\"">>, encode({0, 0, 0}, #{codecs => [timestamp]})). 80 | 81 | datetime_codec_test(Config) when is_list(Config) -> 82 | ?assertEqual( 83 | <<"\"1970-01-01T00:00:00Z\"">>, 84 | encode({{1970, 01, 01}, {00, 00, 00}}, #{codecs => [datetime]}) 85 | ). 86 | 87 | ipv4_codec_test(Config) when is_list(Config) -> 88 | [ 89 | ?assertError(unsupported_tuple, encode({0, 0, 0, 256}, #{codecs => [ipv4]})), 90 | ?assertEqual(<<"\"0.0.0.0\"">>, encode({0, 0, 0, 0}, #{codecs => [ipv4]})) 91 | ]. 92 | 93 | ipv6_codec_test(Config) when is_list(Config) -> 94 | [ 95 | ?assertError(unsupported_tuple, encode({0, 0, 0, 0, 0, 0, 0, -1}, #{codecs => [ipv6]})), 96 | ?assertEqual( 97 | <<"\"fe80::204:acff:fe17:bf38\"">>, 98 | encode({16#fe80, 0, 0, 0, 16#204, 16#acff, 16#fe17, 16#bf38}, #{codecs => [ipv6]}) 99 | ) 100 | ]. 101 | 102 | -record(foo, {foo, bar}). 103 | -record(bar, {bar, baz}). 104 | -if(?OTP_RELEASE >= 26). 105 | records_codec_test(Config) when is_list(Config) -> 106 | [ 107 | ?assertError( 108 | unsupported_tuple, 109 | encode({foo, bar, baz, qux}, #{ 110 | codecs => [ 111 | {records, #{ 112 | foo => {record_info(fields, foo), record_info(size, foo)} 113 | }} 114 | ] 115 | }) 116 | ), 117 | ?assertEqual( 118 | <<"[{\"foo\":\"foo\",\"bar\":\"bar\"},{\"bar\":\"bar\",\"baz\":\"baz\"}]">>, 119 | encode( 120 | [ 121 | #foo{foo = foo, bar = bar}, 122 | #bar{bar = bar, baz = baz} 123 | ], 124 | #{ 125 | codecs => [ 126 | {records, #{ 127 | foo => {record_info(fields, foo), record_info(size, foo)}, 128 | bar => {record_info(fields, bar), record_info(size, bar)} 129 | }} 130 | ] 131 | } 132 | ) 133 | ) 134 | ]. 135 | -else. 136 | records_codec_test(Config) when is_list(Config) -> 137 | [ 138 | ?assertError( 139 | unsupported_tuple, 140 | encode({foo, bar, baz, qux}, #{ 141 | codecs => [ 142 | {records, #{ 143 | foo => {record_info(fields, foo), record_info(size, foo)} 144 | }} 145 | ] 146 | }) 147 | ), 148 | ?assertEqual( 149 | <<"[{\"foo\":\"foo\",\"bar\":\"bar\"},{\"baz\":\"baz\",\"bar\":\"bar\"}]">>, 150 | encode( 151 | [ 152 | #foo{foo = foo, bar = bar}, 153 | #bar{bar = bar, baz = baz} 154 | ], 155 | #{ 156 | codecs => [ 157 | {records, #{ 158 | foo => {record_info(fields, foo), record_info(size, foo)}, 159 | bar => {record_info(fields, bar), record_info(size, bar)} 160 | }} 161 | ] 162 | } 163 | ) 164 | ) 165 | ]. 166 | -endif. 167 | 168 | nulls_test(Config) when is_list(Config) -> 169 | [ 170 | ?assertEqual(<<"null">>, encode(null)), 171 | ?assertEqual(<<"\"null\"">>, encode(null, #{nulls => []})) 172 | ]. 173 | 174 | skip_values_test(Config) when is_list(Config) -> 175 | [ 176 | ?assertEqual(<<"{\"foo\":\"bar\"}">>, encode(#{foo => bar, baz => undefined})), 177 | ?assertEqual( 178 | <<"{\"foo\":\"bar\",\"baz\":\"undefined\"}">>, 179 | encode(#{foo => bar, baz => undefined}, #{skip_values => []}) 180 | ) 181 | ]. 182 | 183 | -if(?OTP_RELEASE >= 26). 184 | key_to_binary_test(Config) when is_list(Config) -> 185 | [ 186 | ?assertEqual( 187 | <<"{\"0\":0,\"bar\":\"bar\",\"baz\":\"baz\",\"foo\":\"foo\"}">>, 188 | encode(#{ 189 | <<"foo">> => foo, 190 | bar => bar, 191 | "baz" => baz, 192 | 0 => 0 193 | }) 194 | ), 195 | ?assertEqual( 196 | <<"{\"hello\":\"world\"}">>, 197 | encode(#{foo => world}, #{key_to_binary => fun(_) -> <<"hello">> end}) 198 | ) 199 | ]. 200 | -else. 201 | key_to_binary_test(Config) when is_list(Config) -> 202 | [ 203 | ?assertEqual( 204 | <<"{\"foo\":\"foo\",\"baz\":\"baz\",\"bar\":\"bar\",\"0\":0}">>, 205 | encode(#{ 206 | <<"foo">> => foo, 207 | bar => bar, 208 | "baz" => baz, 209 | 0 => 0 210 | }) 211 | ), 212 | ?assertEqual( 213 | <<"{\"hello\":\"world\"}">>, 214 | encode(#{foo => world}, #{key_to_binary => fun(_) -> <<"hello">> end}) 215 | ) 216 | ]. 217 | -endif. 218 | 219 | sort_keys_test(Config) when is_list(Config) -> 220 | [ 221 | ?assertEqual(<<"{}">>, encode(#{}, #{sort_keys => true})), 222 | ?assertEqual( 223 | <<"{\"1\":1,\"2\":2,\"3\":3}">>, 224 | encode(#{3 => 3, 1 => 1, 2 => 2}, #{sort_keys => true}) 225 | ) 226 | ]. 227 | 228 | proplists_test(Config) when is_list(Config) -> 229 | [ 230 | ?assertEqual(<<"[]">>, encode([], #{proplists => true})), 231 | ?assertEqual(<<"[\"foo\",\"bar\"]">>, encode([foo, bar], #{proplists => true})), 232 | ?assertEqual(<<"{\"foo\":\"bar\"}">>, encode([{<<"foo">>, bar}], #{proplists => true})), 233 | ?assertEqual(<<"{\"foo\":\"bar\"}">>, encode([{"foo", bar}], #{proplists => true})), 234 | ?assertEqual(<<"{\"foo\":\"bar\"}">>, encode([{foo, bar}], #{proplists => true})), 235 | ?assertEqual(<<"{\"0\":0}">>, encode([{0, 0}], #{proplists => true})), 236 | ?assertEqual(<<"[]">>, encode([], #{proplists => {true, fun(_) -> false end}})), 237 | ?assertEqual( 238 | <<"{\"foo\":\"bar\"}">>, 239 | encode([{foo, bar}], #{proplists => {true, fun([{_, _}]) -> true end}}) 240 | ) 241 | ]. 242 | 243 | escape_test(Config) when is_list(Config) -> 244 | ?assertEqual(<<"bar">>, encode(foo, #{escape => fun(_) -> <<"bar">> end})). 245 | 246 | encode_integer_test(Config) when is_list(Config) -> 247 | ?assertEqual(<<"0">>, encode(0)). 248 | 249 | encode_float_test(Config) when is_list(Config) -> 250 | ?assertEqual(<<"0.0001">>, encode(0.0001)). 251 | 252 | encode_atom_test(Config) when is_list(Config) -> 253 | [ 254 | ?assertEqual(<<"true">>, encode(true)), 255 | ?assertEqual(<<"false">>, encode(false)), 256 | ?assertEqual(<<"null">>, encode(null)), 257 | ?assertEqual(<<"\"foo\"">>, encode(foo)) 258 | ]. 259 | 260 | encode_list_test(Config) when is_list(Config) -> 261 | [ 262 | ?assertEqual(<<"[]">>, encode([])), 263 | ?assertEqual(<<"[\"foo\",\"bar\"]">>, encode([foo, bar])) 264 | ]. 265 | 266 | encode_map_test(Config) when is_list(Config) -> 267 | [ 268 | ?assertEqual(<<"{}">>, encode(#{})), 269 | ?assertEqual(<<"{\"foo\":\"bar\"}">>, encode(#{foo => bar})), 270 | ?assertEqual( 271 | <<"[]">>, 272 | encode(#{}, #{ 273 | encode_map => fun(Map, State) -> 274 | euneus_encoder:continue(maps:to_list(Map), State) 275 | end 276 | }) 277 | ) 278 | ]. 279 | 280 | encode_tuple_test(Config) when is_list(Config) -> 281 | [ 282 | ?assertError(unsupported_tuple, encode({})), 283 | ?assertEqual( 284 | <<"[]">>, 285 | encode({}, #{ 286 | encode_tuple => fun(Tuple, State) -> 287 | euneus_encoder:continue(tuple_to_list(Tuple), State) 288 | end 289 | }) 290 | ) 291 | ]. 292 | 293 | encode_pid_test(Config) when is_list(Config) -> 294 | [ 295 | ?assertError(unsupported_pid, encode(list_to_pid("<0.66.6>"))), 296 | ?assertEqual( 297 | <<"\"<0.66.6>\"">>, 298 | encode(list_to_pid("<0.66.6>"), #{ 299 | encode_pid => fun(Pid, State) -> 300 | euneus_encoder:continue(iolist_to_binary(pid_to_list(Pid)), State) 301 | end 302 | }) 303 | ) 304 | ]. 305 | 306 | encode_port_test(Config) when is_list(Config) -> 307 | [ 308 | ?assertError(unsupported_port, encode(list_to_port("#Port<0.1>"))), 309 | ?assertEqual( 310 | <<"\"#Port<0.1>\"">>, 311 | encode(list_to_port("#Port<0.1>"), #{ 312 | encode_port => fun(Port, State) -> 313 | euneus_encoder:continue(iolist_to_binary(port_to_list(Port)), State) 314 | end 315 | }) 316 | ) 317 | ]. 318 | 319 | encode_reference_test(Config) when is_list(Config) -> 320 | [ 321 | ?assertError( 322 | unsupported_reference, encode(list_to_ref("#Ref<0.314572725.1088159747.110918>")) 323 | ), 324 | ?assertEqual( 325 | <<"\"#Ref<0.314572725.1088159747.110918>\"">>, 326 | encode( 327 | list_to_ref("#Ref<0.314572725.1088159747.110918>"), #{ 328 | encode_reference => fun(Ref, State) -> 329 | euneus_encoder:continue(iolist_to_binary(ref_to_list(Ref)), State) 330 | end 331 | } 332 | ) 333 | ) 334 | ]. 335 | 336 | encode_term_test(Config) when is_list(Config) -> 337 | [ 338 | ?assertError(unsupported_term, encode(fun() -> error end)), 339 | ?assertNotException( 340 | error, 341 | unsupported_term, 342 | encode( 343 | fun() -> ok end, 344 | #{ 345 | encode_term => 346 | fun(Fun, State) when is_function(Fun) -> 347 | euneus_encoder:continue( 348 | iolist_to_binary(erlang:fun_to_list(Fun)), State 349 | ) 350 | end 351 | } 352 | ) 353 | ) 354 | ]. 355 | 356 | %% -------------------------------------------------------------------- 357 | %% Test support 358 | %% -------------------------------------------------------------------- 359 | 360 | encode(Term) -> 361 | euneus:encode(Term). 362 | 363 | encode(Term, Opts) -> 364 | euneus:encode(Term, Opts). 365 | -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/number_-9223372036854775808.json: -------------------------------------------------------------------------------- 1 | [-9223372036854775808] 2 | -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/number_-9223372036854775809.json: -------------------------------------------------------------------------------- 1 | [-9223372036854775809] 2 | -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/number_1.0.json: -------------------------------------------------------------------------------- 1 | [1.0] 2 | -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/number_1.000000000000000005.json: -------------------------------------------------------------------------------- 1 | [1.000000000000000005] 2 | -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/number_1000000000000000.json: -------------------------------------------------------------------------------- 1 | [1000000000000000] 2 | -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/number_10000000000000000999.json: -------------------------------------------------------------------------------- 1 | [10000000000000000999] 2 | -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/number_1e-999.json: -------------------------------------------------------------------------------- 1 | [1E-999] 2 | -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/number_1e6.json: -------------------------------------------------------------------------------- 1 | [1E6] 2 | -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/number_9223372036854775807.json: -------------------------------------------------------------------------------- 1 | [9223372036854775807] 2 | -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/number_9223372036854775808.json: -------------------------------------------------------------------------------- 1 | [9223372036854775808] 2 | -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/object_key_nfc_nfd.json: -------------------------------------------------------------------------------- 1 | {"é":"NFC","é":"NFD"} -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/object_key_nfd_nfc.json: -------------------------------------------------------------------------------- 1 | {"é":"NFD","é":"NFC"} -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/object_same_key_different_values.json: -------------------------------------------------------------------------------- 1 | {"a":1,"a":2} -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/object_same_key_same_value.json: -------------------------------------------------------------------------------- 1 | {"a":1,"a":1} -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/object_same_key_unclear_values.json: -------------------------------------------------------------------------------- 1 | {"a":0, "a":-0} 2 | -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/string_1_escaped_invalid_codepoint.json: -------------------------------------------------------------------------------- 1 | ["\uD800"] -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/string_1_invalid_codepoint.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_encoder_SUITE_data/string_1_invalid_codepoint.json -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/string_2_escaped_invalid_codepoints.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800"] -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/string_2_invalid_codepoints.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_encoder_SUITE_data/string_2_invalid_codepoints.json -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/string_3_escaped_invalid_codepoints.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\uD800"] -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/string_3_invalid_codepoints.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamthome/euneus/29a9f355f6fadcbd50c9a7e786f7a68ddc8bd6c2/test/euneus_encoder_SUITE_data/string_3_invalid_codepoints.json -------------------------------------------------------------------------------- /test/euneus_encoder_SUITE_data/string_with_escaped_NULL.json: -------------------------------------------------------------------------------- 1 | ["A\u0000B"] -------------------------------------------------------------------------------- /test/euneus_formatter_SUITE.erl: -------------------------------------------------------------------------------- 1 | -module(euneus_formatter_SUITE). 2 | -behaviour(ct_suite). 3 | -include_lib("stdlib/include/assert.hrl"). 4 | -compile([export_all, nowarn_export_all]). 5 | 6 | %% -------------------------------------------------------------------- 7 | %% Behaviour (ct_suite) callbacks 8 | %% -------------------------------------------------------------------- 9 | 10 | all() -> 11 | [ 12 | Fun 13 | || {Fun, 1} <- ?MODULE:module_info(exports), 14 | re:run(atom_to_binary(Fun), <<".*_test$">>) =/= nomatch 15 | ]. 16 | 17 | %% -------------------------------------------------------------------- 18 | %% Tests 19 | %% ------------------------------------------------------------------- 20 | 21 | format_test(Config) when is_list(Config) -> 22 | [ 23 | ?assertEqual( 24 | <<"{\r\t\t\"foo\":\"bar\"\r}">>, 25 | format(<<"\r\n\t{\"foo\":\"bar\"}">>, #{ 26 | indent_type => tabs, 27 | indent_width => 2, 28 | spaced_values => false, 29 | crlf => r 30 | }) 31 | ), 32 | ?assertEqual( 33 | <<"[\r\n\t\t\"foo\",\r\n\t\t\"bar\"\r\n]">>, 34 | format(<<"[\"foo\",\"bar\"]">>, #{ 35 | indent_type => tabs, 36 | indent_width => 2, 37 | spaced_values => false, 38 | crlf => rn 39 | }) 40 | ), 41 | ?assertEqual( 42 | << 43 | "[\n true,\n false,\n null,\n {\n " 44 | "\"foo\": \"b\\\"ar\",\n \"bar\": 0\n }\n]" 45 | >>, 46 | format( 47 | <<"[true, false, null, {\"foo\":\"b\\\"ar\", \"bar\": 0}]">>, 48 | #{ 49 | indent_type => spaces, 50 | indent_width => 2, 51 | spaced_values => true, 52 | crlf => n 53 | } 54 | ) 55 | ) 56 | ]. 57 | 58 | %% -------------------------------------------------------------------- 59 | %% Test support 60 | %% -------------------------------------------------------------------- 61 | 62 | format(JSON, Opts) -> 63 | euneus:format(JSON, Opts). 64 | --------------------------------------------------------------------------------