#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
:copyright:
    Lion Krischer (lionkrischer@gmail.com), 2016
:license:
    MIT License
"""
import os
import platform

import h5netcdf
import numpy as np
import pytest

from pyexodus import exodus
from pyexodus.compat import get_dim_size

_p = [
    {"io_size": 4, "word_size": 4, "f_dtype": np.float32},
    {"io_size": 8, "word_size": 8, "f_dtype": np.float64},
]

if platform.architecture()[0] == "64bit":  # pragma: no cover
    _p.append(
        {"io_size": 0, "word_size": 8, "f_dtype": np.float64},
    )
else:  # pragma: no cover
    _p.append(
        {"io_size": 0, "word_size": 4, "f_dtype": np.float32},
    )


@pytest.fixture(params=_p, ids=["io_size_%i" % _i["io_size"] for _i in _p])
def io_size(request):
    """
    Fixture to parametrize over the io_sizes.
    """
    return request.param


def to_string(x):
    return x.decode() if isinstance(x, bytes) else x


def normalize(v):
    v = to_string(v)
    if isinstance(v, np.ndarray) and len(v) == 1:
        v = v[0]
    if hasattr(h5netcdf, "Dimension") and isinstance(v, h5netcdf.Dimension):
        if v.isunlimited() is False:
            v = v.size
        elif v.size == 0:
            v = None
        else:
            breakpoint()
            pass
    return v


def norm_dict(d):
    """
    Attempt to get dicts the same, independent of the h5netcdf version.
    """
    return {normalize(k): normalize(v) for k, v in dict(d).items()}


def test_initialization(tmpdir, io_size):
    """
    Tests initialization.

    Test data has been generated by using the official exodus Python API.
    """
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.close()

    # Just manually test everything.
    with h5netcdf.File(filename, mode="r") as f:
        assert norm_dict(f.attrs) == norm_dict(
            {
                "api_version": np.array([7.05], dtype=np.float32),
                "file_size": np.array([1], dtype=np.int32),
                "floating_point_word_size": np.array(
                    [io_size["word_size"]], dtype=np.int32
                ),
                "int64_status": np.array([0], dtype=np.int32),
                "maximum_name_length": np.array([32], dtype=np.int32),
                "title": b"Example",
                "version": np.array([7.05], dtype=np.float32),
            }
        )

        assert norm_dict(dict(f.dimensions)) == {
            "four": 4,
            "len_line": 81,
            "len_name": 256,
            "len_string": 33,
            "num_dim": 3,
            "num_el_blk": 1,
            "num_elem": 6,
            "num_nodes": 5,
            "num_side_sets": 1,
            "time_step": None,
        }

        assert list(f.groups) == []

        # Testing the variables is a bit more effort.

        # Generate with
        # v = f.variables
        # {k: {"dimensions": v[k].dimensions,
        #      "shape": v[k].shape,
        #      "dtype": v[k].dtype,
        #      "attrs": dict(v[k].attrs),
        #      "data": v[k][:]} for k in f.variables.keys()} == \

        expected = {
            "coor_names": {
                "attrs": {},
                "data": np.array(
                    [[""] * 256, [""] * 256, [""] * 256], dtype="|S1"
                ),
                "dimensions": ("num_dim", "len_name"),
                "dtype": np.dtype("S1"),
                "shape": (3, 256),
            },
            "coordx": {
                "attrs": {},
                "data": np.array([0.0, 0.0, 0.0, 0.0, 0.0]),
                "dimensions": ("num_nodes",),
                "dtype": io_size["f_dtype"],
                "shape": (5,),
            },
            "coordy": {
                "attrs": {},
                "data": np.array([0.0, 0.0, 0.0, 0.0, 0.0]),
                "dimensions": ("num_nodes",),
                "dtype": io_size["f_dtype"],
                "shape": (5,),
            },
            "coordz": {
                "attrs": {},
                "data": np.array([0.0, 0.0, 0.0, 0.0, 0.0]),
                "dimensions": ("num_nodes",),
                "dtype": io_size["f_dtype"],
                "shape": (5,),
            },
            "eb_names": {
                "attrs": {},
                "data": np.array([[""] * 256], dtype="|S1"),
                "dimensions": ("num_el_blk", "len_name"),
                "dtype": np.dtype("S1"),
                "shape": (1, 256),
            },
            "eb_prop1": {
                "attrs": {"name": b"ID"},
                "data": np.array([-1], dtype=np.int32),
                "dimensions": ("num_el_blk",),
                "dtype": np.dtype("int32"),
                "shape": (1,),
            },
            "eb_status": {
                "attrs": {},
                "data": np.array([0], dtype=np.int32),
                "dimensions": ("num_el_blk",),
                "dtype": np.dtype("int32"),
                "shape": (1,),
            },
            "ss_names": {
                "attrs": {},
                "data": np.array([[""] * 256], dtype="|S1"),
                "dimensions": ("num_side_sets", "len_name"),
                "dtype": np.dtype("S1"),
                "shape": (1, 256),
            },
            "ss_prop1": {
                "attrs": {"name": b"ID"},
                "data": np.array([-1], dtype=np.int32),
                "dimensions": ("num_side_sets",),
                "dtype": np.dtype("int32"),
                "shape": (1,),
            },
            "ss_status": {
                "attrs": {},
                "data": np.array([0], dtype=np.int32),
                "dimensions": ("num_side_sets",),
                "dtype": np.dtype("int32"),
                "shape": (1,),
            },
            "time_whole": {
                "attrs": {},
                "data": np.array([], dtype=io_size["f_dtype"]),
                "dimensions": ("time_step",),
                "dtype": io_size["f_dtype"],
                "shape": (0,),
            },
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert norm_dict(dict(a.attrs)) == norm_dict(e["attrs"]), key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_coords(tmpdir, io_size):
    """
    Tests the put_coords() method.
    """
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.put_info_records(info=[])

    # Use different dtypes on purpose to test the type conversions.
    e.put_coords(
        xCoords=np.arange(5, dtype=np.float32),
        yCoords=np.arange(5, dtype=np.int32) * 2,
        zCoords=np.arange(5, dtype=np.int64) * 3,
    )

    e.close()

    expected = {
        "coordx": {
            "attrs": {},
            "data": np.array([0.0, 1.0, 2.0, 3.0, 4.0]),
            "dimensions": ("num_nodes",),
            "dtype": io_size["f_dtype"],
            "shape": (5,),
        },
        "coordy": {
            "attrs": {},
            "data": np.array([0.0, 2.0, 4.0, 6.0, 8.0]),
            "dimensions": ("num_nodes",),
            "dtype": io_size["f_dtype"],
            "shape": (5,),
        },
        "coordz": {
            "attrs": {},
            "data": np.array([0.0, 3.0, 6.0, 9.0, 12.0]),
            "dimensions": ("num_nodes",),
            "dtype": io_size["f_dtype"],
            "shape": (5,),
        },
    }

    with h5netcdf.File(filename, mode="r") as f:
        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_elem_blk_info(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.put_info_records(info=[])

    # Use different dtypes on purpose to test the type conversions.
    e.put_coords(
        xCoords=np.arange(5, dtype=np.float32),
        yCoords=np.arange(5, dtype=np.int32) * 2,
        zCoords=np.arange(5, dtype=np.int64) * 3,
    )

    e.put_elem_blk_info(1, "HEX", 6, 3, 0)

    e.close()

    with h5netcdf.File(filename, mode="r") as f:
        # Two new dimensions.
        assert get_dim_size(f, "num_el_in_blk1") == 6
        assert get_dim_size(f, "num_nod_per_el1") == 3

        # One new variable.
        expected = {
            "connect1": {
                "attrs": {"elem_type": b"HEX"},
                "data": np.zeros((6, 3), dtype=np.int32),
                "dimensions": ("num_el_in_blk1", "num_nod_per_el1"),
                "dtype": np.int32,
                "shape": (6, 3),
            },
            "eb_status": {
                "attrs": {},
                "data": np.ones(1),
                "dimensions": ("num_el_blk",),
                "dtype": np.int32,
                "shape": (1,),
            },
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert norm_dict(dict(a.attrs)) == norm_dict(e["attrs"]), key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_elem_connectivity(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.put_info_records(info=[])

    # Use different dtypes on purpose to test the type conversions.
    e.put_coords(
        xCoords=np.arange(5, dtype=np.float32),
        yCoords=np.arange(5, dtype=np.int32) * 2,
        zCoords=np.arange(5, dtype=np.int64) * 3,
    )

    e.put_elem_blk_info(1, "HEX", 6, 3, 0)
    e.put_elem_connectivity(1, np.arange(6 * 3) + 7)

    e.close()

    with h5netcdf.File(filename, mode="r") as f:
        # connect1 should now be filled.
        expected = {
            "connect1": {
                "attrs": {"elem_type": b"HEX"},
                "data": (np.arange(6 * 3) + 7).reshape((6, 3)),
                "dimensions": ("num_el_in_blk1", "num_nod_per_el1"),
                "dtype": np.int32,
                "shape": (6, 3),
            }
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert norm_dict(dict(a.attrs)) == norm_dict(e["attrs"]), key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_elem_connectivity_indices_shift(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.put_info_records(info=[])

    # Use different dtypes on purpose to test the type conversions.
    e.put_coords(
        xCoords=np.arange(5, dtype=np.float32),
        yCoords=np.arange(5, dtype=np.int32) * 2,
        zCoords=np.arange(5, dtype=np.int64) * 3,
    )

    e.put_elem_blk_info(1, "HEX", 6, 3, 0)
    e.put_elem_connectivity(1, np.arange(6 * 3) + 7, shift_indices=3)

    e.close()

    with h5netcdf.File(filename, mode="r") as f:
        # connect1 should now be filled.
        expected = {
            "connect1": {
                "attrs": {"elem_type": b"HEX"},
                "data": (np.arange(6 * 3) + 7).reshape((6, 3)) + 3,
                "dimensions": ("num_el_in_blk1", "num_nod_per_el1"),
                "dtype": np.int32,
                "shape": (6, 3),
            }
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert norm_dict(dict(a.attrs)) == norm_dict(e["attrs"]), key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_time(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.put_time(1, 1.1)

    with h5netcdf.File(filename, mode="r") as f:
        np.testing.assert_allclose(f.variables["time_whole"], [1.1])


def test_set_global_variable_number(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.set_global_variable_number(3)

    with h5netcdf.File(filename, mode="r") as f:
        _d = np.empty((3, 256), dtype="|S1")
        _d.fill("")

        expected = {
            "name_glo_var": {
                "attrs": {},
                "data": _d,
                "dimensions": ("num_glo_var", "len_name"),
                "dtype": np.dtype("|S1"),
                "shape": (3, 256),
            },
            "vals_glo_var": {
                "attrs": {},
                "data": np.zeros((0, 3)),
                "dimensions": ("time_step", "num_glo_var"),
                "dtype": io_size["f_dtype"],
                "shape": (0, 3),
            },
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_global_variable_name(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.set_global_variable_number(3)
    e.put_global_variable_name(name="hello", index=2)

    _d = np.empty((3, 256), dtype="|S1")
    _d.fill("")
    _d[1][:5] = list("hello")

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "name_glo_var": {
                "attrs": {},
                "data": _d,
                "dimensions": ("num_glo_var", "len_name"),
                "dtype": np.dtype("|S1"),
                "shape": (3, 256),
            }
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_get_global_variable_names(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")
    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.set_global_variable_number(3)
    e.put_global_variable_name(name="hello", index=2)
    assert e.get_global_variable_names() == ["", "hello", ""]


def test_put_global_variable_value(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.set_global_variable_number(3)
    e.put_global_variable_name(name="hello", index=2)

    e.put_global_variable_value("hello", 1, 1.1)

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "vals_glo_var": {
                "attrs": {},
                "data": np.array([[0, 1.1, 0]], dtype=io_size["f_dtype"]),
                "dimensions": ("time_step", "num_glo_var"),
                "dtype": io_size["f_dtype"],
                "shape": (1, 3),
            }
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_set_element_variables(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    # This call does nothing.
    e.set_element_variable_number(0)

    # This does something.
    e.set_element_variable_number(5)
    e.close()

    _d = np.empty((5, 256), dtype="|S1")
    _d.fill("")

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "name_elem_var": {
                "attrs": {},
                "data": _d,
                "dimensions": ("num_elem_var", "len_name"),
                "dtype": np.dtype("|S1"),
                "shape": (5, 256),
            }
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_element_variable_name(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.set_element_variable_number(5)
    e.put_element_variable_name("random", 3)
    e.close()

    _d = np.empty((5, 256), dtype="|S1")
    _d.fill("")
    _d[2][:6] = list("random")

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "name_elem_var": {
                "attrs": {},
                "data": _d,
                "dimensions": ("num_elem_var", "len_name"),
                "dtype": np.dtype("|S1"),
                "shape": (5, 256),
            }
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_get_element_variable_names(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.set_element_variable_number(5)
    e.put_element_variable_name("random", 3)

    assert e.get_element_variable_names() == ["", "", "random", "", ""]


def test_put_element_variable_values(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.set_element_variable_number(5)
    e.put_element_variable_name("random", 3)
    # requires an actual element block.
    e.put_elem_blk_info(1, "HEX", 6, 3, 0)
    e.put_element_variable_values(1, "random", 1, np.arange(6))

    e.close()

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "vals_elem_var3eb1": {
                "attrs": {},
                "data": np.arange(6, dtype=io_size["f_dtype"]).reshape(1, 6),
                "dimensions": ("time_step", "num_el_in_blk1"),
                "dtype": io_size["f_dtype"],
                "shape": (1, 6),
            }
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_set_node_variable_number(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.set_node_variable_number(2)

    _d = np.empty((2, 256), dtype="|S1")
    _d.fill("")

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "name_nod_var": {
                "attrs": {},
                "data": _d,
                "dimensions": ("num_nod_var", "len_name"),
                "dtype": np.dtype("|S1"),
                "shape": (2, 256),
            },
            "vals_nod_var1": {
                "attrs": {},
                "data": np.zeros((0, 5)),
                "dimensions": ("time_step", "num_nodes"),
                "dtype": io_size["f_dtype"],
                "shape": (0, 5),
            },
            "vals_nod_var2": {
                "attrs": {},
                "data": np.zeros((0, 5)),
                "dimensions": ("time_step", "num_nodes"),
                "dtype": io_size["f_dtype"],
                "shape": (0, 5),
            },
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_get_node_variable_number(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    assert e.get_node_variable_number() == 0
    e.set_node_variable_number(2)
    assert e.get_node_variable_number() == 2
    e.close()

    e = exodus(filename, mode="r")
    assert e.get_node_variable_number() == 2
    e.close()


def test_put_node_variable_name(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.set_node_variable_number(2)
    e.put_node_variable_name("good friend", 1)

    _d = np.empty((2, 256), dtype="|S1")
    _d.fill("")
    _d[0][:11] = list("good friend")

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "name_nod_var": {
                "attrs": {},
                "data": _d,
                "dimensions": ("num_nod_var", "len_name"),
                "dtype": np.dtype("|S1"),
                "shape": (2, 256),
            }
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_multiple_node_variable_names(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.set_node_variable_number(2)
    e.put_node_variable_name("good friend", 1)
    e.put_node_variable_name("how are you?", 2)

    _d = np.empty((2, 256), dtype="|S1")
    _d.fill("")
    _d[0][:11] = list("good friend")
    _d[1][:12] = list("how are you?")

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "name_nod_var": {
                "attrs": {},
                "data": _d,
                "dimensions": ("num_nod_var", "len_name"),
                "dtype": np.dtype("|S1"),
                "shape": (2, 256),
            }
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_node_variable_values(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.set_node_variable_number(2)
    e.put_node_variable_name("good friend", 1)
    e.put_node_variable_values("good friend", 1, np.arange(5))

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "vals_nod_var1": {
                "attrs": {},
                "data": np.arange(5).reshape((1, 5)),
                "dimensions": ("time_step", "num_nodes"),
                "dtype": io_size["f_dtype"],
                "shape": (1, 5),
            }
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_side_set_params(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.put_side_set_params(4, 5, 0)
    e.close()

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "elem_ss1": {
                "attrs": {},
                "data": np.zeros(5),
                "dimensions": ("num_side_ss1",),
                "dtype": np.int32,
                "shape": (5,),
            },
            "side_ss1": {
                "attrs": {},
                "data": np.zeros(5),
                "dimensions": ("num_side_ss1",),
                "dtype": np.int32,
                "shape": (5,),
            },
            "ss_prop1": {
                "attrs": {"name": b"ID"},
                "data": np.array([4], dtype=np.int32),
                "dimensions": ("num_side_sets",),
                "dtype": np.dtype("int32"),
                "shape": (1,),
            },
            "ss_status": {
                "attrs": {},
                "data": np.array([1], dtype=np.int32),
                "dimensions": ("num_side_sets",),
                "dtype": np.dtype("int32"),
                "shape": (1,),
            },
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert norm_dict(dict(a.attrs)) == norm_dict(e["attrs"]), key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_side_set(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.put_side_set_params(4, 5, 0)
    e.put_side_set(
        4, np.ones(5, dtype=np.int32) * 2, np.ones(5, dtype=np.int32) * 3
    )
    e.close()

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "elem_ss1": {
                "attrs": {},
                "data": [2, 2, 2, 2, 2],
                "dimensions": ("num_side_ss1",),
                "dtype": np.int32,
                "shape": (5,),
            },
            "side_ss1": {
                "attrs": {},
                "data": [3, 3, 3, 3, 3],
                "dimensions": ("num_side_ss1",),
                "dtype": np.int32,
                "shape": (5,),
            },
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_side_set_name(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.put_side_set_params(4, 5, 0)
    e.put_side_set(
        4, np.ones(5, dtype=np.int32) * 2, np.ones(5, dtype=np.int32) * 3
    )
    e.put_side_set_name(4, "edge of the world")
    e.close()

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "ss_names": {
                "attrs": {},
                "data": np.array(
                    [
                        [
                            "e",
                            "d",
                            "g",
                            "e",
                            " ",
                            "o",
                            "f",
                            " ",
                            "t",
                            "h",
                            "e",
                            " ",
                            "w",
                            "o",
                            "r",
                            "l",
                            "d",
                        ]
                        + [""] * 239
                    ],
                    dtype="|S1",
                ),
                "dimensions": ("num_side_sets", "len_name"),
                "dtype": np.dtype("S1"),
                "shape": (1, 256),
            }
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_multiple_side_set_names(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=2,
        io_size=io_size["io_size"],
    )
    e.put_side_set_params(4, 5, 0)
    e.put_side_set_params(7, 2, 0)
    e.put_side_set_name(4, "edge of the world")
    e.put_side_set_name(7, "a new beginning")
    e.close()

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "ss_names": {
                "attrs": {},
                "data": np.array(
                    [
                        [
                            "e",
                            "d",
                            "g",
                            "e",
                            " ",
                            "o",
                            "f",
                            " ",
                            "t",
                            "h",
                            "e",
                            " ",
                            "w",
                            "o",
                            "r",
                            "l",
                            "d",
                        ]
                        + [""] * 239,
                        [
                            "a",
                            " ",
                            "n",
                            "e",
                            "w",
                            " ",
                            "b",
                            "e",
                            "g",
                            "i",
                            "n",
                            "n",
                            "i",
                            "n",
                            "g",
                        ]
                        + [""] * 241,
                    ],
                    dtype="|S1",
                ),
                "dimensions": ("num_side_sets", "len_name"),
                "dtype": np.dtype("S1"),
                "shape": (2, 256),
            }
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_usage_as_context_manager(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    with exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    ) as e:
        e.put_time(1, 1.1)

    with h5netcdf.File(filename, mode="r") as f:
        np.testing.assert_allclose(f.variables["time_whole"], [1.1])


def test_status_in_file_with_two_side_sets_only_one_set(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    with exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=2,
        io_size=io_size["io_size"],
    ) as e:
        e.put_side_set_params(4, 5, 0)

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "ss_prop1": {
                "attrs": {"name": b"ID"},
                "data": np.array([4, -1], dtype=np.int32),
                "dimensions": ("num_side_sets",),
                "dtype": np.dtype("int32"),
                "shape": (2,),
            },
            "ss_status": {
                "attrs": {},
                "data": np.array([1, 0], dtype=np.int32),
                "dimensions": ("num_side_sets",),
                "dtype": np.dtype("int32"),
                "shape": (2,),
            },
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert norm_dict(dict(a.attrs)) == norm_dict(e["attrs"]), key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_status_in_file_with_two_side_sets_with_two_set(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    with exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=2,
        io_size=io_size["io_size"],
    ) as e:
        e.put_side_set_params(4, 5, 0)
        e.put_side_set_params(7, 2, 0)

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "ss_prop1": {
                "attrs": {"name": b"ID"},
                "data": np.array([4, 7], dtype=np.int32),
                "dimensions": ("num_side_sets",),
                "dtype": np.dtype("int32"),
                "shape": (2,),
            },
            "ss_status": {
                "attrs": {},
                "data": np.array([1, 1], dtype=np.int32),
                "dimensions": ("num_side_sets",),
                "dtype": np.dtype("int32"),
                "shape": (2,),
            },
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert norm_dict(dict(a.attrs)) == norm_dict(e["attrs"]), key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_filling_two_side_sets(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    with exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=2,
        io_size=io_size["io_size"],
    ) as e:
        e.put_side_set_params(4, 5, 0)
        e.put_side_set_params(7, 2, 0)
        e.put_side_set(
            4, np.ones(5, dtype=np.int32) * 2, np.ones(5, dtype=np.int32) * 3
        )
        e.put_side_set(
            7, np.ones(2, dtype=np.int32) * 7, np.ones(2, dtype=np.int32) * 8
        )

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "elem_ss1": {
                "attrs": {},
                "data": [2, 2, 2, 2, 2],
                "dimensions": ("num_side_ss1",),
                "dtype": np.int32,
                "shape": (5,),
            },
            "side_ss1": {
                "attrs": {},
                "data": [3, 3, 3, 3, 3],
                "dimensions": ("num_side_ss1",),
                "dtype": np.int32,
                "shape": (5,),
            },
            "elem_ss2": {
                "attrs": {},
                "data": [7, 7],
                "dimensions": ("num_side_ss2",),
                "dtype": np.int32,
                "shape": (2,),
            },
            "side_ss2": {
                "attrs": {},
                "data": [8, 8],
                "dimensions": ("num_side_ss2",),
                "dtype": np.int32,
                "shape": (2,),
            },
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_put_info_records(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    with exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=2,
        io_size=io_size["io_size"],
    ) as e:
        e.put_info_records(["", "how", "are", "you"])

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "info_records": {
                "attrs": {},
                "data": np.array(
                    [
                        [
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                        ],
                        [
                            "h",
                            "o",
                            "w",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                        ],
                        [
                            "a",
                            "r",
                            "e",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                        ],
                        [
                            "y",
                            "o",
                            "u",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                        ],
                    ],
                    dtype="|S1",
                ),
                "dimensions": ("num_info", "len_line"),
                "dtype": np.dtype("S1"),
                "shape": (4, 81),
            }
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert dict(a.attrs) == e["attrs"], key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_compression(tmpdir, io_size):
    """
    Test to make sure compressions does something.
    """
    filename = os.path.join(tmpdir.strpath, "example.e")

    # No compression at first.
    with exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=2,
        io_size=io_size["io_size"],
    ):
        pass

    with h5netcdf.File(filename) as f:
        for var in f._variables:
            ds = f._variables[var]._h5ds
            assert ds.compression is None, ds
            assert ds.compression_opts is None, ds
            # Time arrays are resizeable so they must be chunked.
            if ds.name == "/time_whole":
                assert ds.chunks, ds
            else:
                assert ds.chunks is None, ds

    os.remove(filename)

    # No turn on compression.
    with exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=2,
        compression=("gzip", 2),
        io_size=io_size["io_size"],
    ):
        pass

    with h5netcdf.File(filename) as f:
        for var in f._variables:
            ds = f._variables[var]._h5ds
            assert ds.compression == "gzip", ds
            assert ds.compression_opts == 2, ds
            # Compression forces chunking.
            assert ds.chunks, ds


def test_init_multiple_element_blocks(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=3,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.close()

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "eb_names": {
                "attrs": {},
                "data": np.array(
                    [[""] * 256, [""] * 256, [""] * 256], dtype="|S1"
                ),
                "dimensions": ("num_el_blk", "len_name"),
                "dtype": np.dtype("S1"),
                "shape": (3, 256),
            },
            "eb_prop1": {
                "attrs": {"name": b"ID"},
                "data": np.array([-1, -1, -1], dtype=np.int32),
                "dimensions": ("num_el_blk",),
                "dtype": np.dtype("int32"),
                "shape": (3,),
            },
            "eb_status": {
                "attrs": {},
                "data": np.array([0, 0, 0], dtype=np.int32),
                "dimensions": ("num_el_blk",),
                "dtype": np.dtype("int32"),
                "shape": (3,),
            },
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert norm_dict(dict(a.attrs)) == norm_dict(e["attrs"]), key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_init_multiple_element_blocks_and_set_first_one(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=3,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.put_elem_blk_info(7, "SEVEN", 6, 3, 0)
    e.close()

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "eb_names": {
                "attrs": {},
                "data": np.array(
                    [[""] * 256, [""] * 256, [""] * 256], dtype="|S1"
                ),
                "dimensions": ("num_el_blk", "len_name"),
                "dtype": np.dtype("S1"),
                "shape": (3, 256),
            },
            "connect1": {
                "attrs": {"elem_type": b"SEVEN"},
                "data": np.zeros((6, 3), dtype=np.int32),
                "dimensions": ("num_el_in_blk1", "num_nod_per_el1"),
                "dtype": np.int32,
                "shape": (6, 3),
            },
            "eb_prop1": {
                "attrs": {"name": b"ID"},
                "data": np.array([7, -1, -1], dtype=np.int32),
                "dimensions": ("num_el_blk",),
                "dtype": np.dtype("int32"),
                "shape": (3,),
            },
            "eb_status": {
                "attrs": {},
                "data": np.array([1, 0, 0], dtype=np.int32),
                "dimensions": ("num_el_blk",),
                "dtype": np.dtype("int32"),
                "shape": (3,),
            },
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert norm_dict(dict(a.attrs)) == norm_dict(e["attrs"]), key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_init_multiple_element_blocks_and_set_all(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")

    e = exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=3,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    )
    e.put_elem_blk_info(7, "SEVEN", 6, 3, 0)
    e.put_elem_blk_info(1, "ONE", 6, 3, 0)
    e.put_elem_blk_info(3, "THREE", 6, 3, 0)
    e.close()

    with h5netcdf.File(filename, mode="r") as f:
        expected = {
            "eb_names": {
                "attrs": {},
                "data": np.array(
                    [[""] * 256, [""] * 256, [""] * 256], dtype="|S1"
                ),
                "dimensions": ("num_el_blk", "len_name"),
                "dtype": np.dtype("S1"),
                "shape": (3, 256),
            },
            "connect1": {
                "attrs": {"elem_type": b"SEVEN"},
                "data": np.zeros((6, 3), dtype=np.int32),
                "dimensions": ("num_el_in_blk1", "num_nod_per_el1"),
                "dtype": np.int32,
                "shape": (6, 3),
            },
            "connect2": {
                "attrs": {"elem_type": b"ONE"},
                "data": np.zeros((6, 3), dtype=np.int32),
                "dimensions": ("num_el_in_blk2", "num_nod_per_el2"),
                "dtype": np.int32,
                "shape": (6, 3),
            },
            "connect3": {
                "attrs": {"elem_type": b"THREE"},
                "data": np.zeros((6, 3), dtype=np.int32),
                "dimensions": ("num_el_in_blk3", "num_nod_per_el3"),
                "dtype": np.int32,
                "shape": (6, 3),
            },
            "eb_prop1": {
                "attrs": {"name": b"ID"},
                "data": np.array([7, 1, 3], dtype=np.int32),
                "dimensions": ("num_el_blk",),
                "dtype": np.dtype("int32"),
                "shape": (3,),
            },
            "eb_status": {
                "attrs": {},
                "data": np.array([1, 1, 1], dtype=np.int32),
                "dimensions": ("num_el_blk",),
                "dtype": np.dtype("int32"),
                "shape": (3,),
            },
        }

        for key in sorted(expected.keys()):
            a = f.variables[key]
            e = expected[key]

            assert norm_dict(dict(a.attrs)) == norm_dict(e["attrs"]), key
            np.testing.assert_equal(a[:], e["data"], err_msg=key)
            assert a.dimensions == e["dimensions"], key
            assert a.dtype == e["dtype"], key
            assert a.shape == e["shape"], key


def test_get_elem_type_for_block(tmpdir, io_size):
    filename = os.path.join(tmpdir.strpath, "example.e")
    with exodus(
        filename,
        mode="w",
        title="Example",
        array_type="numpy",
        numDims=3,
        numNodes=5,
        numElems=6,
        numBlocks=1,
        numNodeSets=0,
        numSideSets=1,
        io_size=io_size["io_size"],
    ) as e:
        e.put_coords(
            xCoords=np.arange(5), yCoords=np.arange(5), zCoords=np.arange(5)
        )
        e.put_elem_blk_info(1, "HEX", 6, 3, 0)

        assert e.get_elem_type_for_block(1) == "HEX"

        with pytest.raises(ValueError) as err:
            e.get_elem_type_for_block(2)
        assert err.value.args[0] == "No element block with id 2 in file."
