Skip to content

Commit 5c44380

Browse files
committed
Replaces scaffold tests with concrete test implementations
1 parent 90bf326 commit 5c44380

27 files changed

+731
-460
lines changed
Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,53 @@
1-
# Auto-generated scaffold. Replace TODOs with concrete tests.
2-
import pytest
31
import numpy as np
42

5-
# expected vs actual helpers
63

7-
def _assert_equal(expected, actual):
8-
assert expected == actual
4+
def test_calculate_r_metrics_and_chi_square():
5+
from easydiffraction.analysis.fit_helpers import metrics as M
96

7+
y_obs = np.array([1.0, 2.0, 3.0])
8+
y_calc = np.array([1.1, 1.9, 2.8])
9+
weights = np.array([1.0, 2.0, 3.0])
10+
residuals = y_obs - y_calc
1011

11-
# Module under test: easydiffraction.analysis.fit_helpers.metrics
12+
r = M.calculate_r_factor(y_obs, y_calc)
13+
rb = M.calculate_rb_factor(y_obs, y_calc)
14+
rw = M.calculate_weighted_r_factor(y_obs, y_calc, weights)
15+
r2 = M.calculate_r_factor_squared(y_obs, y_calc)
16+
chi2 = M.calculate_reduced_chi_square(residuals, num_parameters=1)
1217

13-
# TODO: Replace with real, small tests per class/method.
14-
# Keep names explicit: expected_*, actual_*; compare in a single assert.
18+
assert 0 <= r <= 1 and np.isfinite(r)
19+
assert np.isclose(r, rb)
20+
assert np.isfinite(rw)
21+
assert np.isfinite(r2)
22+
assert np.isfinite(chi2)
1523

16-
def test_module_import():
17-
import easydiffraction.analysis.fit_helpers.metrics as MUT
18-
expected_module_name = "easydiffraction.analysis.fit_helpers.metrics"
19-
actual_module_name = MUT.__name__
20-
_assert_equal(expected_module_name, actual_module_name)
24+
25+
def test_get_reliability_inputs_collects_arrays_with_default_su():
26+
from easydiffraction.analysis.fit_helpers import metrics as M
27+
28+
# Minimal fakes for experiments
29+
class DS:
30+
def __init__(self):
31+
self.meas = np.array([1.0, 2.0])
32+
self.meas_su = None # triggers default ones
33+
self.calc = np.array([1.1, 1.9])
34+
35+
class Expt:
36+
def __init__(self):
37+
self.datastore = DS()
38+
39+
class Expts(dict):
40+
def values(self):
41+
return [Expt()]
42+
43+
class SampleModels(dict):
44+
pass
45+
46+
class Calc:
47+
def calculate_pattern(self, sample_models, experiment):
48+
# no-op; calc already set in DS
49+
return None
50+
51+
y_obs, y_calc, y_err = M.get_reliability_inputs(SampleModels(), Expts(), Calc())
52+
assert y_obs.shape == (2,) and y_calc.shape == (2,) and y_err.shape == (2,)
53+
assert np.allclose(y_err, 1.0)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
def test_how_to_access_parameters_prints_paths_and_uids(capsys):
2+
from easydiffraction.analysis.analysis import Analysis
3+
from easydiffraction.core.parameters import Parameter
4+
from easydiffraction.core.validation import AttributeSpec, DataTypes
5+
from easydiffraction.io.cif.handler import CifHandler
6+
7+
# Build two parameters with identity metadata set directly
8+
def make_param(db, cat, entry, name, val):
9+
p = Parameter(
10+
name=name,
11+
value_spec=AttributeSpec(value=val, type_=DataTypes.NUMERIC, default=0.0),
12+
cif_handler=CifHandler(names=[f'_{cat}.{name}']),
13+
)
14+
# Inject identity metadata (avoid parent chain)
15+
p._identity.datablock_entry_name = lambda: db
16+
p._identity.category_code = cat
17+
if entry:
18+
p._identity.category_entry_name = lambda: entry
19+
else:
20+
p._identity.category_entry_name = lambda: ''
21+
return p
22+
23+
p1 = make_param('db1', 'catA', '', 'alpha', 1.0)
24+
p2 = make_param('db2', 'catB', 'row1', 'beta', 2.0)
25+
26+
class Coll:
27+
def __init__(self, params):
28+
self.parameters = params
29+
30+
class Project:
31+
_varname = 'proj'
32+
def __init__(self):
33+
self.sample_models = Coll([p1])
34+
self.experiments = Coll([p2])
35+
36+
a = Analysis(Project())
37+
a.how_to_access_parameters()
38+
out = capsys.readouterr().out
39+
assert 'How to access parameters' in out
40+
# Expect code path strings
41+
assert "proj.sample_models['db1'].catA.alpha" in out
42+
assert "proj.experiments['db2'].catB['row1'].beta" in out
43+
# Expect CIF uid (owner.unique_name) present for both
44+
assert 'db1.catA.alpha' in out
45+
assert 'db2.catB.row1.beta' in out
Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,34 @@
11
from easydiffraction.core.category import CategoryCollection, CategoryItem
2-
from easydiffraction.core.parameters import GenericDescriptorBase
2+
from easydiffraction.core.parameters import StringDescriptor
33
from easydiffraction.core.validation import AttributeSpec, DataTypes
4-
from easydiffraction.io.cif.serialize import category_item_to_cif
5-
6-
7-
class SimpleDescriptor(GenericDescriptorBase):
8-
_value_type = DataTypes.STRING
9-
def __init__(self, name, value):
10-
super().__init__(
11-
name=name,
12-
description='',
13-
value_spec=AttributeSpec(value=value, type_=DataTypes.STRING, default=''),
14-
)
4+
from easydiffraction.io.cif.handler import CifHandler
155

166

177
class SimpleItem(CategoryItem):
188
def __init__(self, entry_name):
199
super().__init__()
2010
self._identity.category_code = 'simple'
2111
self._identity.category_entry_name = entry_name
22-
# Assign as private attributes to bypass GuardedBase writable checks,
23-
# and expose via properties below.
24-
object.__setattr__(self, '_a', SimpleDescriptor('a', 'x'))
25-
object.__setattr__(self, '_b', SimpleDescriptor('b', 'y'))
12+
object.__setattr__(
13+
self,
14+
'_a',
15+
StringDescriptor(
16+
name='a',
17+
description='',
18+
value_spec=AttributeSpec(value='x', type_=DataTypes.STRING, default=''),
19+
cif_handler=CifHandler(names=['_simple.a']),
20+
),
21+
)
22+
object.__setattr__(
23+
self,
24+
'_b',
25+
StringDescriptor(
26+
name='b',
27+
description='',
28+
value_spec=AttributeSpec(value='y', type_=DataTypes.STRING, default=''),
29+
cif_handler=CifHandler(names=['_simple.b']),
30+
),
31+
)
2632

2733
@property
2834
def a(self):
@@ -52,24 +58,5 @@ def test_category_collection_str_and_cif_calls():
5258
c.add(SimpleItem('n2'))
5359
s = str(c)
5460
assert 'collection' in s and '2 items' in s
55-
# as_cif delegates to serializer; calling it ensures code path executed
56-
_ = c.as_cif# Auto-generated scaffold. Replace TODOs with concrete tests.
57-
import pytest
58-
import numpy as np
59-
60-
# expected vs actual helpers
61-
62-
def _assert_equal(expected, actual):
63-
assert expected == actual
64-
65-
66-
# Module under test: easydiffraction.core.category
67-
68-
# TODO: Replace with real, small tests per class/method.
69-
# Keep names explicit: expected_*, actual_*; compare in a single assert.
70-
71-
def test_module_import():
72-
import easydiffraction.core.category as MUT
73-
expected_module_name = "easydiffraction.core.category"
74-
actual_module_name = MUT.__name__
75-
_assert_equal(expected_module_name, actual_module_name)
61+
# as_cif delegates to serializer; should be a string (possibly empty)
62+
assert isinstance(c.as_cif, str)
Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,3 @@
1-
# Auto-generated scaffold. Replace TODOs with concrete tests.
2-
import pytest
3-
import numpy as np
4-
5-
# expected vs actual helpers
6-
7-
def _assert_equal(expected, actual):
8-
assert expected == actual
9-
10-
11-
# Module under test: easydiffraction.core.collection
12-
13-
# TODO: Replace with real, small tests per class/method.
14-
# Keep names explicit: expected_*, actual_*; compare in a single assert.
15-
16-
def test_module_import():
17-
import easydiffraction.core.collection as MUT
18-
expected_module_name = "easydiffraction.core.collection"
19-
actual_module_name = MUT.__name__
20-
_assert_equal(expected_module_name, actual_module_name)
21-
22-
231
def test_collection_add_get_delete_and_names():
242
from easydiffraction.core.collection import CollectionBase
253
from easydiffraction.core.identity import Identity
@@ -38,17 +16,13 @@ def as_cif(self) -> str:
3816
return ""
3917

4018
c = MyCollection(item_type=Item)
41-
# add two items
4219
a = Item("a")
4320
b = Item("b")
4421
c["a"] = a
4522
c["b"] = b
46-
# get
4723
assert c["a"] is a and c["b"] is b
48-
# overwrite existing key
4924
a2 = Item("a")
5025
c["a"] = a2
5126
assert c["a"] is a2 and len(list(c.keys())) == 2
52-
# delete
5327
del c["b"]
5428
assert list(c.names) == ["a"]
Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,71 @@
1-
# Auto-generated scaffold. Replace TODOs with concrete tests.
21
import pytest
3-
import numpy as np
42

5-
# expected vs actual helpers
63

7-
def _assert_equal(expected, actual):
8-
assert expected == actual
9-
10-
11-
# Module under test: easydiffraction.core.datablock
12-
13-
# TODO: Replace with real, small tests per class/method.
14-
# Keep names explicit: expected_*, actual_*; compare in a single assert.
15-
16-
def test_module_import():
17-
import easydiffraction.core.datablock as MUT
18-
expected_module_name = "easydiffraction.core.datablock"
19-
actual_module_name = MUT.__name__
20-
_assert_equal(expected_module_name, actual_module_name)
21-
22-
23-
def test_datablock_collection_add_and_filters():
4+
def test_datablock_collection_add_and_filters_with_real_parameters():
245
from easydiffraction.core.datablock import DatablockCollection, DatablockItem
6+
from easydiffraction.core.category import CategoryItem
257
from easydiffraction.core.parameters import Parameter
26-
from easydiffraction.core.identity import Identity
8+
from easydiffraction.core.validation import AttributeSpec, DataTypes
9+
from easydiffraction.io.cif.handler import CifHandler
2710

28-
class DummyParam:
29-
def __init__(self, name, free=True, constrained=False):
30-
self.free = free
31-
self.constrained = constrained
32-
self._identity = Identity(owner=self, category_entry=lambda: name)
11+
class Cat(CategoryItem):
12+
def __init__(self):
13+
super().__init__()
14+
self._identity.category_code = 'cat'
15+
self._identity.category_entry_name = 'e1'
16+
# real Parameters
17+
self._p1 = Parameter(
18+
name='p1',
19+
description='',
20+
value_spec=AttributeSpec(value=1.0, type_=DataTypes.NUMERIC, default=0.0),
21+
units='',
22+
cif_handler=CifHandler(names=['_cat.p1']),
23+
)
24+
self._p2 = Parameter(
25+
name='p2',
26+
description='',
27+
value_spec=AttributeSpec(value=2.0, type_=DataTypes.NUMERIC, default=0.0),
28+
units='',
29+
cif_handler=CifHandler(names=['_cat.p2']),
30+
)
31+
# Make p2 constrained and not free
32+
self._p2._constrained = True
33+
self._p2._free = False
34+
# Mark p1 free to be included in free_parameters
35+
self._p1.free = True
36+
37+
@property
38+
def p1(self):
39+
return self._p1
40+
41+
@property
42+
def p2(self):
43+
return self._p2
3344

3445
class Block(DatablockItem):
35-
def __init__(self, name, params):
46+
def __init__(self, name):
3647
super().__init__()
48+
# set datablock entry name
3749
self._identity.datablock_entry_name = lambda: name
38-
self._params = params
39-
40-
@property
41-
def parameters(self):
42-
return self._params
50+
# include the category as attribute so DatablockItem.parameters picks them up
51+
self._cat = Cat()
4352

4453
@property
45-
def as_cif(self) -> str:
46-
return ""
54+
def cat(self):
55+
return self._cat
4756

4857
coll = DatablockCollection(item_type=Block)
49-
a = Block("A", [DummyParam("p1", free=True, constrained=False)])
50-
b = Block("B", [DummyParam("p2", free=False, constrained=False), DummyParam("p3", free=True, constrained=True)])
58+
a = Block('A')
59+
b = Block('B')
5160
coll.add(a)
5261
coll.add(b)
53-
# aggregate
54-
assert len(coll.parameters) == 3
55-
# fittable: Parameter subclass and not constrained -> here 0 because DummyParam not Parameter
56-
assert coll.fittable_parameters == []
57-
# free: subset of fittable -> empty
58-
assert coll.free_parameters == []
62+
# parameters collection aggregates from both blocks (p1 & p2 each)
63+
params = coll.parameters
64+
assert len(params) == 4
65+
# fittable excludes constrained parameters
66+
fittable = coll.fittable_parameters
67+
assert all(isinstance(p, Parameter) for p in fittable)
68+
assert len(fittable) == 2 # only p1 from each block
69+
# free is subset of fittable where free=True (true for p1)
70+
free_params = coll.free_parameters
71+
assert free_params == fittable

0 commit comments

Comments
 (0)