Compare commits

...
Author SHA1 Message Date
skylar taylor-barrick ef24afc10c #618: move the OFFSET canvas test into the ui-egui test binary
Main now builds one integration-test binary per crate (#1989); only tests that install process-wide state stay separate. This test only drives its own session, so it joins tests/it.
2026-10-23 12:18:39 -06:00
skylar taylor-barrick 6528bb564b Merge remote-tracking branch 'origin/main' into test/backfill-regression-tests 2026-10-23 12:09:53 -06:00
aiongg 37150774c6 CI: run the gate through craft-common-actions' shared gate.yml; FreeBSD nightly and on release (#1987)
ci.yml is new: it calls the shared workflow (cached apt packages, nextest, main-only cache saves, Cargo.lock check). FreeBSD and Windows ARM64 run nightly and on pushes to release instead of on pull requests. Depends on storytold/craft-common-actions#69.
2026-10-23 13:56:16 -04:00
aiongg 9cf115e808 CI: one test binary per crate, nextest, line tables only (#1989)
* Build: line tables only in dev, no debug info for dependencies

* Tests: one integration-test binary per crate

Each crate's tests/*.rs becomes a module of tests/it/main.rs. Files that
install process-wide state (the file io hooks, user aliases, SAVETIME and
SAVEFILEPATH, user linetype and pattern files, registered fonts) stay their
own test binaries.

* xtask ci: nextest, tests without examples, one wasm check call
2026-10-23 13:34:26 -04:00
skylar taylor-barrick d0281360c2 #618: finish the grid-snapped OFFSET in the canvas test
The test stopped once the source line was picked, so a broken side-point step could leave the drawing unchanged and still pass. It now clicks a side point above the line and checks that the copy lands 5 units up, at y = 7. It also checks that OFFSET asks for the next object and that Enter ends it.
2026-10-22 21:16:48 -06:00
skylar taylor-barrick de5aecfe8b #651: compare small text against the plot build path
The full-detail baseline used build(), which takes the on-screen path; plots take build_plot(), which keeps glyphs at full detail and records them as plot text. Comparing against build_plot() checks what the test's name says. With the screen-detail change reverted it still fails (480 triangles on screen, 480 in the plot).
2026-10-22 16:49:30 -06:00
skylar taylor-barrick 546b5a1cf3 #651: test that small filled text is simplified on screen and keeps full detail in plots
Filled TrueType text was triangulated at full outline detail at every zoom, which froze the canvas on pages of small text. The test builds four O glyphs on screen at 10 px and under 2 px per em and checks the triangle count drops (to one box per glyph at the smallest), while a plot keeps every triangle. Without the fix the on-screen build has the same 1656 triangles as the plot. It skips when no system font is installed, like the other TrueType render tests.
2026-10-22 16:34:32 -06:00
skylar taylor-barrick 2ab09850bb #1336: test that the DXF LAYER table stops at the record cap
The LAYER, LTYPE, STYLE and DIMSTYLE tables had no record cap, unlike VIEW, UCS and VPORT. The test reads a DXF with over a million LAYER records and checks the layer list stays at the cap; without the guard it holds every record (1000102 layers). The other three tables scan their lists linearly per record, so a million-record file is too slow to build in a test and they stay uncovered.
2026-10-22 16:34:32 -06:00
skylar taylor-barrick 4ab8c384b3 #618: test that OFFSET takes a clicked distance and picks its source under grid snap
OFFSET only accepted a typed distance, and with grid snap on a click meant to pick the source object was moved to the nearest grid point. The engine test clicks two points for the distance and checks the guide, the distance and the resulting offset; the canvas test does the same through grid-snapped clicks and then picks the source line. Without the fix the engine test stays at the distance prompt and the canvas test never picks the line.
2026-10-22 16:34:32 -06:00
283 changed files with 502 additions and 39 deletions
+30
View File
@@ -0,0 +1,30 @@
name: CI
# Quality gates for every push to main and every pull request (`cargo xtask ci`), through the
# suite's shared gate workflow in craft-common-actions.
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
permissions:
contents: read
# A newer push to a PR branch cancels its older run; every push to main runs to the end.
concurrency:
group: ci-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
gate:
# Tracks @main so suite-wide CI fixes reach every app without a PR in each repository.
uses: storytold/craft-common-actions/.github/workflows/gate.yml@main
with:
# Same craft-fonts commit as release.yml.
craft-fonts-ref: 3d9ab3a132ed0eff457e424226a435a901da30d3
timeout-minutes: 90
packages: >-
pkg-config libxkbcommon-dev libwayland-dev libx11-dev libxcb1-dev libxcursor-dev
libxrandr-dev libxi-dev libfontconfig1-dev libfreetype-dev mesa-vulkan-drivers
libgl1-mesa-dev
+3
View File
@@ -2,6 +2,9 @@
# (GitHub has no FreeBSD runners). GPU tests skip themselves when the VM has no adapter.
name: FreeBSD
# The VM build is slow, so it runs nightly on main and on pushes to `release`, not on every pull
# request: a drifted dependency still shows up within a day, and always before a release ships.
# PRs that change the FreeBSD workflow or packaging itself still run it.
on:
push:
branches: [release]
+4 -2
View File
@@ -3,15 +3,17 @@
# binaries are ARM64, run the CLI natively, and uninstall.
name: Windows ARM64
# Nightly on main and on pushes to `release` (dependency and runner-image drift shows up within a
# day, and always before a release ships), and on PRs that change the Windows packaging itself.
on:
schedule:
- cron: "3 5 * * *"
push:
branches: [release]
pull_request:
paths:
- .github/workflows/windows-arm64.yml
- packaging/windows/**
schedule:
- cron: "41 3 * * 1"
workflow_dispatch:
concurrency:
+2
View File
@@ -69,9 +69,11 @@ type_complexity = "allow"
[profile.dev.package."*"]
opt-level = 2
debug = false
[profile.dev]
opt-level = 1
debug = "line-tables-only"
[profile.release]
opt-level = 3
+6
View File
@@ -0,0 +1,6 @@
mod cli;
mod drafting_spacing;
mod help;
mod mcp_connect;
mod skipped_records;
mod undrawn_entities;
+2
View File
@@ -0,0 +1,2 @@
mod lin_pat_parse;
mod sub_segment_alias;
@@ -29,7 +29,7 @@ fn session() -> (Session, Handle) {
/// As [`session`], with the fixture's text changed by `edit` first.
fn session_with(edit: impl Fn(String) -> String) -> (Session, Handle) {
let grip = "0 BLOCKLINEARGRIP\n5 68\n330 61\n100 AcDbEvalExpr\n90 9\n98 33\n99 232\n100 AcDbBlockElement\n300 End Grip\n98 33\n99 232\n1071 0\n";
let src = include_str!("../../io/tests/data/dynblock_door.txt")
let src = include_str!("../../../io/tests/data/dynblock_door.txt")
.replace("\r\n", "\n")
.replace("170 4\n91 0\n91 0\n", "170 4\n91 8\n91 9\n")
.replace("1030 0\n93 0\n170 0\n171 0\n100 AcDbBlockVisibilityParameter", "1030 0\n93 10\n170 0\n171 0\n100 AcDbBlockVisibilityParameter")
@@ -2,7 +2,6 @@
//! leave exactly the expected entities, layers and printed text. The corpus lives in its own
//! repository; point `CADCRAFT_LISP_CORPUS` at its `cases` directory (or the repository) to run
//! it. Without it the test only says so.
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
use std::path::{Path, PathBuf};
+143
View File
@@ -0,0 +1,143 @@
mod angle_prompts;
mod angle_settings;
mod annotate_options;
mod annotative;
mod arc_ctrl_direction;
mod array_commands;
mod assoc_array;
mod attdisp_attsync;
mod attedit_prompts;
mod attrib_modes;
mod attrib_props;
mod attribute_tools;
mod block_keep;
mod block_redefine;
mod break_closed_polyline;
mod break_join_locked_layers;
mod break_keeps_z;
mod burst;
mod constraint_geometry;
mod constraint_infer;
mod count;
mod dash_block;
mod data_extraction;
mod dim_baseline_spacing;
mod dim_chain;
mod dim_commands;
mod dim_explode_text;
mod dim_properties;
mod dim_radial_inside;
mod dim_radial_outside;
mod dim_vars;
mod dimtedit_prompts;
mod drafting_spacing;
mod draw_prompts;
mod draworder;
mod dyn_input;
mod dynamic_block_data;
mod dynamic_grips;
mod fillet_chamfer;
mod fix_holds_grips;
mod followups_626;
mod grip_dim_input;
mod grip_options;
mod grip_selection;
mod group_selection;
mod groups;
mod hatch_assoc;
mod hatch_dialog_helpers;
mod hatch_numeric_validation;
mod hatch_options;
mod helix;
mod inquiry_keywords;
mod inquiry_z;
mod insert_prompts;
mod isometric;
mod join_close;
mod json_param_validation;
mod layer_cmdline;
mod layer_merge_delete;
mod layoff_repeat;
mod layout_prompts;
#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
mod lisp_corpus;
mod malformed_handles;
mod matchprop;
mod measure_distance_snapping;
mod metric_linetypes;
mod mleader_content;
mod mleader_remember;
mod mline;
mod mocoro;
mod modify_curves;
mod mtext_columns;
mod mtext_options;
mod multiline_attributes;
mod named_views;
mod non_finite_edits;
mod offset_closed_spline;
mod offset_ellipse_side;
mod offset_move;
mod options_profile;
mod overkill;
mod parallel_display_list;
mod pedit_splinedit;
mod pick_text;
mod pickdrag;
mod pline_arc_xline_options;
mod plot_styles;
mod point_modifiers;
mod post_command_passes;
mod prompt_keywords;
mod props_bad_lineweight;
mod props_insert_scale_attribs;
mod purge_mlinestyles;
mod purge_prompts;
mod qdim;
mod qdim_modes;
mod query_entities;
mod quickcalc;
mod recent_commands;
mod rectang_ortho;
mod refedit;
mod region;
mod rename_cmdline;
mod rotate_reference;
mod select_keywords;
mod select_similar;
mod select_underscore_keywords;
mod selection_cycling;
mod selection_modes;
mod setvar_coverage;
mod shapes;
mod snap_annotations;
mod snap_blocks;
mod snap_curves;
mod snap_intersections_aperture;
mod snap_nearest;
mod snap_overrides;
mod snap_tracking;
mod snaps_more;
mod space_is_enter;
mod spline_degree;
mod spline_options;
mod stretch;
mod stretch_select;
mod table_formulas;
mod table_styles;
mod temp_tracking;
mod text_commands;
mod text_left_justify;
mod tolerance;
mod transparent;
mod trim_closed_polyline;
mod trim_extend_options;
mod undo_count;
mod undo_layout_tab;
mod viewport_clip;
mod vplayer_prompts;
mod vports;
mod xdata_follows_entity;
mod zoom_keywords;
mod zoom_viewport;
mod zoom_window_ortho;
@@ -1,7 +1,9 @@
//! OFFSET Erase/Layer/Multiple/Undo and the MOVE/COPY Displacement option at the command line.
use cadcraft_engine::Input;
use cadcraft_engine::Session;
use cadcraft_engine::doc::EntityKind;
use cadcraft_engine::geom::Vec2;
use serde_json::json;
/// Every line as ((ax, ay), (bx, by), layer), sorted by the first y.
@@ -62,6 +64,27 @@ fn offset_multiple_and_undo() {
assert_eq!(lines(&s), vec![l((0.0, 0.0), (10.0, 0.0), "0"), l((0.0, 2.0), (10.0, 2.0), "0"), l((0.0, 4.0), (10.0, 4.0), "0")]);
}
// Regression test for #618: OFFSET's distance prompt took only a typed number; clicking two points
// (the distance between them) was rejected, and the second click had no distance guide.
#[test]
fn offset_distance_from_two_clicked_points() {
let mut s = one_line();
s.start("offset").unwrap();
s.input(Input::Point(Vec2::new(20.0, 20.0))).unwrap();
let p = s.current_prompt().unwrap();
assert!(p.message.contains("second point"), "{}", s.prompt_text());
assert!(p.base.is_some_and(|b| b.near(Vec2::new(20.0, 20.0), 1e-9)), "the second click is measured from the first");
// The guide from the first click to the cursor is the previewed distance.
let guide = s.preview(Vec2::new(20.0, 22.5));
assert!(matches!(guide.first().map(|e| &e.kind), Some(EntityKind::Line(g)) if g.a.xy().near(Vec2::new(20.0, 20.0), 1e-9)), "{guide:?}");
s.input(Input::Point(Vec2::new(20.0, 22.5))).unwrap();
assert!(s.current_prompt().unwrap().message.contains("Select object"), "{}", s.prompt_text());
assert_eq!(s.doc().unwrap().header.f64("OFFSETDIST", -1.0), 2.5);
s.script("5,0 5,1\n\n").unwrap();
assert!(s.running.is_none(), "{}", s.prompt_text());
assert_eq!(lines(&s), vec![l((0.0, 0.0), (10.0, 0.0), "0"), l((0.0, 2.5), (10.0, 2.5), "0")]);
}
#[test]
fn offset_json_erase_and_layer() {
let mut s = one_line();

Some files were not shown because too many files have changed in this diff Show More