Files
Aislo/resources/tester/test_est_text_units.py

401 lines
16 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""원본 가시설·측량설계 산근에서 발췌한 단위와 설명 열의 계산 시험."""
from test_est_rea_parity import run
def test_replace_cost_words_preserves_markers_and_checks_lengths_before_changes():
result = run(
"math",
r"""(()=>{
const rows=[{index:3,row:{LineData:'\x0e모래\x0e + 모래 = \x121\x12'}},{index:5,row:{LineData:'유지'}}];
const before=JSON.stringify(rows),changed=EstText.replaceWords(rows,'모래','자갈');let rejected=0;
for(const [a,b] of [['','x'],['모래','\x12'],['모래','x'.repeat(200001)]]){
try{EstText.replaceWords(rows,a,b)}catch{rejected++}
}
const markers=EstText.replaceWords([{index:7,row:{LineData:'Q=1 = \x121\x12; cost \x031\x03'}}],'1','2');
const calcRows=[{Index:1,Code:'H',LineData:'head'},{LineData:'Q=1 = \x121\x12'}];
const update=EstText.replaceWords([{row:calcRows[1],index:1}],'1','2')[0];calcRows[1].LineData=update.value;
const recalculated=EstText.calculate(calcRows);
return {changed,rejected,markers,unchanged:JSON.stringify(rows)===before,
crossing:EstText.replaceWords(rows,'모래 +','x').length,recalculated:recalculated.rows[1].LineData,errors:recalculated.errors};
})()""",
)
assert result["changed"] == [{"index": 3, "value": "\x0e자갈\x0e + 자갈 = \x121\x12"}]
assert result["rejected"] == 3
assert result["markers"] == [{"index": 7, "value": "Q=2 = \x121\x12; cost \x031\x03"}]
assert "\x122\x12" in result["recalculated"] and not result["errors"]
assert result["unchanged"] and result["crossing"] == 0
def test_text_units_and_description_columns_preserve_numeric_assignments():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'units',LineData:'units'},
{LineData:' G2 = 3.14 / 4 ×0.105^2 ×1.50M × 2배 = \x120.026\x12 ㎥',Precision:3},
{LineData:' N = 2 set'},
{LineData:' 1. 재료비 : D=16mm, 1본당 4.0m'},
{LineData:' Q = D × N = \x1232\x12'},
{LineData:' V = G2 × 1000 = \x1226\x12'}
])""",
)
assert result["errors"] == []
assert result["rows"][1]["TC"] == 0.026
assert result["rows"][4]["TC"] == 32
assert result["rows"][5]["TC"] == 26
def test_text_unit_changes_propagate_without_reusing_stored_results():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'changed',LineData:'changed'},
{LineData:' N = 3 set'},
{LineData:' 1. 재료비 : D=25mm, 1본당 4.0m'},
{LineData:' Q = D × N = \x1232\x12'},
{LineData:' V = 1.5M × 3배 = \x123\x12',Precision:2}
])""",
)
assert result["errors"] == []
assert result["rows"][3]["TC"] == 75
assert result["rows"][4]["TC"] == 4.5
def test_per_set_unicode_millimetres_and_starred_weight_declarations():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'source_units',LineData:'source_units'},
{LineData:' * 본당 중량 W = 0.553톤/본*'},
{LineData:' T = 20㎜ A = 0.95 × 0.95 = \x120.9\x12㎡',Precision:1},
{LineData:' 재료비 : \x031,690\x03 × 0.005kg/set = \x128.4\x12',SCheck:-2},
{LineData:' Q = W × T = \x1211.06\x12',Precision:2}
])""",
)
assert result["errors"] == []
assert result["rows"][2]["TC"] == 0.9
assert result["rows"][3]["TC"] == 8.4
assert result["rows"][4]["TC"] == 11.06
def test_parenthesized_volume_and_count_units_recalculate_from_variables():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'volume',LineData:'volume'},
{LineData:' A = 80㎡ B = 16㎡'},
{LineData:' 새끼 : L =0.05m × 4배 × 4번 × 1줄 = \x120.8\x12m',Precision:1},
{LineData:' 노무비 : \x0358,122\x03 × 0.1 × (A+B)㎥ = 58,122 × 0.1 × (80+16) = \x12557,971.2\x12',SCheck:-1},
{LineData:' Q = L × (A+B)㎡ = \x1276.8\x12',Precision:1}
])""",
)
assert result["errors"] == []
assert result["rows"][2]["TC"] == 0.8
assert result["rows"][3]["TC"] == 557971.2
assert result["rows"][4]["TC"] == 76.8
def test_quoted_source_conversion_declaration_propagates_changed_value():
result = run(
"math",
r"""[2,3].map(quantity=>EstText.calculate([
{Index:1,Code:'quote',LineData:'quote'},
{LineData:` * 중량환산 : 사석기준 'Q1 = ${quantity}.0 톤/㎥'`},
{LineData:' 노무비 : \x03235,204\x03 ×1.04인×Q1 = 235,204 ×1.04×2 = \x12489,224.3\x12',SCheck:-1}
]))""",
)
assert all(item["errors"] == [] for item in result)
assert [item["rows"][2]["TC"] for item in result] == [489224.3, 733836.4]
def test_group_sum_accepts_assigned_price_and_refreshes_from_source():
result = run(
"math",
r"""[550,600].map(price=>{
const p=EstNative.empty();p.options.SourceRefresh=true;
p.tables.StuffcDat=[{Code:'M',ValueIndex:4,InputTC:price}];
p.tables.CostMainDat=[
{Index:1,Code:'C',LineData:'C'},
{LinkIndex:5,Code:'M',LineData:' \x0ebrick\x0e \x06A\x06\x03550\x03 : 별산'},
{LinkIndex:62,SCheck:-1,LineData:' \x07A\x07\x1a550\x1a × 5% = \x1227.5\x12'},
{SCheck:-1,LineData:' \x1a노무비:27\x1a'},
{SCheck:-5,LineData:' \x1a계:\x1a \x1227\x12'}];
p.tables.EstMainDat=[{Code:'C',LinkIndex:104,GN:10},{LinkIndex:54}];
return EstNative.calculate(p);
})""",
)
assert all(item["calculation"]["errors"] == [] for item in result)
assert [item["tables"]["CostMainDat"][2]["TC"] for item in result] == [27.5, 30]
assert [item["tables"]["EstMainDat"][0]["TC"] for item in result] == [270, 300]
def test_subtotal_includes_price_only_rows_and_updates_truncated_final_amount():
result = run(
"math",
r"""[1094,2000].map(price=>{
const p=EstNative.empty();
p.tables.StuffcDat=[{Code:'T',ValueIndex:4,InputTC:110754},{Code:'H',ValueIndex:4,InputTC:price}];
p.tables.CostMainDat=[
{Index:1,Code:'C',LineData:'transport'},
{Level:2,LineData:'1. 운반 및 하역'},
{LinkIndex:5,Code:'T',LineData:' \x0etruck\x0e (\x03110,754\x03 ÷12) ×1.5 = \x1213,844.2\x12'},
{LinkIndex:5,Code:'H',LineData:' \x0eunloading\x0e \x031,094\x03'},
{LinkIndex:61,SCheck:-3,TC:14938.2,LineData:' 경비소계 : \x0c14,938.2\x0c'},
{Level:2,LineData:'2. 합계'},
{Level:-2,SCheck:-3,LineData:' \x1a경비:14,938\x1a'},
{Level:-2,SCheck:-5,LineData:' \x1a계:\x1a \x1214,938\x12'}];
p.tables.EstMainDat=[{Code:'C',LinkIndex:104,GN:10},{LinkIndex:54}];
const first=EstNative.calculate(p),again=EstNative.calculate(first);
return {first,again};
})""",
)
assert all(item["first"]["calculation"]["errors"] == [] for item in result)
assert [item["first"]["tables"]["CostMainDat"][4]["TC"] for item in result] == [
14938.2,
15844.2,
]
for key in ["first", "again"]:
assert [item[key]["tables"]["EstMainDat"][0]["TC"] for item in result] == [
149380,
158440,
]
def test_operator_followed_by_spaces_does_not_start_a_new_assignment():
result = run(
"math",
r"""[1700,2000].map(weight=>EstText.calculate([
{Index:1,Code:'forest',LineData:'forest'},
{LineData:` N = 54.93 q = 250 W = ${weight}`},
{LineData:' Q = N × q ÷ W = 54.93 × 250 ÷ 1,700 = \x128.08\x12 ㎥/hr'},
{LineData:' V = Q × 2 = \x1216.16\x12'}
]))""",
)
assert all(item["errors"] == [] for item in result)
assert [item["rows"][2]["TC"] for item in result] == [8.08, 6.87]
assert [item["rows"][3]["TC"] for item in result] == [16.16, 13.74]
def test_curly_wrapped_results_and_explanatory_calculations_keep_their_text():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'forest',LineData:'forest'},
{LineData:' {0.91m×0.91m×0.6m = \x120.49686\x12㎥}'},
{LineData:' {0.49686 ×2.6Ton = \x121.29\x12}'},
{LineData:' ※ ㎡당 중량 1.6개 ×1,325÷1,000 = \x122.12\x12Ton/㎡'}
])""",
)
assert result["errors"] == []
assert [row["TC"] for row in result["rows"][1:]] == [0.49686, 1.29, 2.12]
assert result["rows"][1]["LineData"].strip().startswith("{")
assert result["rows"][1]["LineData"].endswith("}")
def test_won_unit_glyphs_are_units_instead_of_operators():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'money',LineData:'money'},
{LineData:' 0.0347㎥ / 2.5 × 0 \\/㎥ = \x120\x12'},
{LineData:' 0.0347㎥ / 2.5 × 2500 \\/㎥ = \x1234.7\x12'},
{LineData:' 2㎥ × 2500₩/㎥ = \x125000\x12'}
])""",
)
assert result["errors"] == []
assert [row["TC"] for row in result["rows"][1:]] == [0, 34.7, 5000]
def test_range_conditions_are_not_assigned_arbitrary_values():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'range',LineData:'range'},
{LineData:' 앙카핀 (D=13, L=450~600mm) 1.0㎡ : 별도계상'},
{LineData:' H = 0~4m : (기계80%, 인력20%)'},
{LineData:' Q = 2 × 3 = \x126\x12'},
{LineData:' V = H × 2 = \x128\x12'}
])""",
)
assert len(result["errors"]) == 1
assert "참조 항목 없음: H" in result["errors"][0]
assert result["rows"][3]["TC"] == 6
def test_quantity_subtotal_keeps_six_digits_before_pricing():
result = run(
"math",
r"""[4.4,5].map(length=>EstText.calculate([
{Index:1,Code:'sign',LineData:'sign'},
{Level:2,LineData:'각재 수량'},
{Diget:7,DigetIndex:1,LineData:` 0.09 ×0.09 ×${length}m ×2개 = \x120.07128\x12`},
{Diget:7,DigetIndex:1,LineData:' 0.06 ×0.06 ×2.28m ×5개 = \x120.04104\x12'},
{Diget:7,DigetIndex:1,LineData:' 0.06 ×0.06 ×2.28m ×7개 = \x120.057456\x12'},
{Diget:7,DigetIndex:1,LinkIndex:61,LineData:' 소 계 : Q1 = \x0c0.169776\x0c ㎥/개소'},
{SCheck:-2,LinkIndex:5,LineData:' 재료비 : \x03577,842\x03 × Q1 = 577,842 × 0.169776 = \x1298,103.7\x12'}
]))""",
)
assert all(item["errors"] == [] for item in result)
assert [item["rows"][5]["TC"] for item in result] == [0.169776, 0.179496]
assert [item["rows"][6]["TC"] for item in result] == [98103.7, 103720.3]
def test_declaration_can_follow_an_hour_unit_with_a_single_space():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'transport',LineData:'transport'},
{LineData:' L = 1.0Km{?} V1 = 5.5Km/hr V2 = 9.3Km/hr t=35분'},
{LineData:' Q = t × 2 = \x1270\x12'}
])""",
)
assert result["errors"] == []
assert result["rows"][2]["TC"] == 70
def test_fullwidth_unit_slash_and_ground_level_annotations():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'annotations',LineData:'annotations'},
{LineData:' Q = 23.32 ㎥/hr'},
{LineData:' D1 = {-}6.6m [평균지반고]'},
{LineData:' D2 = {-}18.6m [기초터파기 평균 저면 EL.]'},
{LineData:' V = Q + D1 - D2 = \x1235.32\x12',Precision:2}
])""",
)
assert result["errors"] == []
assert result["rows"][4]["TC"] == 35.32
def test_marine_units_and_bullet_are_treated_as_labels():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'marine'},
{LineData:' q = 2인 ÷12구멍 = \x120.17\x12 인/구멍'},
{LineData:' ⊙ 480분 ÷ 88.42 = \x125.43\x12 본/일'},
{LineData:' 노무비 : \x03156,379\x03 ÷ \x11122.66\x11 × 1척 = \x121,274.8\x12', SCheck:-1},
{LineData:' ◎ 목재길이 L = 5.2m/EA × 3열 × 2단 × 3구역 = \x1293.6\x12 m'}
])""",
)
assert result["errors"] == []
assert [row["TC"] for row in result["rows"][1:]] == [0.17, 5.43, 1274.8, 93.6]
def test_arrow_to_sketch_is_not_a_fraction():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'sketch'},
{LineData:' L = 5.2m ⇒ ───────'},
{LineData:' Q = L × 2 = \x1210.4\x12'}
])""",
)
assert result["errors"] == []
assert result["rows"][2]["TC"] == 10.4
def test_mixed_brackets_in_annotation():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'datum'},
{LineData:' t1 = 5분 〔토운선을 준설선에 접선 소요시간]'},
{LineData:' Q = t1 × 2 = \x1210\x12'}
])""",
)
assert result["errors"] == []
assert result["rows"][2]["TC"] == 10
def test_greek_variables_and_implicit_multiplication_in_marine_formula():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'greek'},
{LineData:' α = 1.0'},
{LineData:' β = 0.6'},
{LineData:' ι = 14.0 N = 7'},
{LineData:' Tb = 0.08×α×β×ι (N + 2)'},
{LineData:' Tc = Tb × 2 = \x1212.10\x12'}
])""",
)
assert result["errors"] == []
assert result["rows"][5]["TC"] == 12.1
def test_parenthesized_variable_label_assigns_explicit_value():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'label'},
{LineData:' 기타시간 (Te) : 10분'},
{LineData:' Tc = Te × 2 = \x1220\x12'}
])""",
)
assert result["errors"] == []
assert result["rows"][2]["TC"] == 20
def test_variable_assignment_with_approximate_annotation():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'approx'},
{LineData:' Q1 = 3.2hr ≒ 0.5일'},
{LineData:' Q = Q1 × 2 = \x126.4\x12'}
])""",
)
assert result["errors"] == []
assert result["rows"][2]["TC"] == 6.4
def test_braced_arithmetic_and_survey_point_units():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'brace'},
{LineData:' Q1 = { 6.0M×0.0002EA/M + 2.3M×0.0005EA/M + 1M×0.0005EA/M }'},
{LineData:' Q = Q1 × 10000 = \x1228.5\x12'},
{LineData:' 노무비 : \x03295,138\x03×3지점÷3지점×3인×4회 = \x123,541,656\x12',SCheck:-1},
{LineData:' B{적재량} = 1500/11.5{5㎥×2.3} = \x12130.43\x12'}
])""",
)
assert result["errors"] == []
assert result["rows"][2]["TC"] == 28.5
assert result["rows"][3]["TC"] == 3541656
assert result["rows"][4]["TC"] == 130.43
def test_marine_compound_units_and_therefore_symbol():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'units'},
{LineData:' 시험 : 2지점×2개항목×4회×11,000= \x12176,000\x12'},
{LineData:' 보고서 : \x0350\x03×70×4분기×5권 = \x1270,000\x12', SCheck:-2},
{LineData:' Q = 4hr/일 × 15일/월 × 65월 = \x123,900\x12'},
{LineData:' ∴ 0.22 ÷ 6㎥ = \x120.04\x12 hr'},
{LineData:' C = ((1,294.95 + 1,174.6) ÷ 1.1) ÷ 5DM/Ton = \x12449\x12원/DM', Precision:0},
{LineData:' 행거 11조당 중량 4.69 × 2 = \x129.38\x12 ㎏'}
])""",
)
assert result["errors"] == []
assert [row["TC"] for row in result["rows"][1:]] == [176000, 70000, 3900, 0.04, 449, 9.38]
def test_spaced_metre_unit_is_not_a_second_variable_declaration():
result = run(
"math",
r"""EstText.calculate([
{Index:1,Code:'spaced_unit',LineData:'spaced_unit'},
{LineData:' L7 = 4.5m'},
{LineData:' Q2 = L7 / 0.8 M = 4.5 / 0.8 = \x125.63\x12 개'},
{SCheck:-2,LineData:' 재료비 : \x033,000\x03 × Q2 = 3,000 × 5.63 = \x1216,890\x12'}
])""",
)
assert result["errors"] == []
assert result["rows"][2]["TC"] == 5.63
assert result["rows"][3]["TC"] == 16890