Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/instructions/code-review.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,19 @@ Avoid LINQ in hot paths and UI code for performance:
- Use array/list indexing instead of `.First()` / `.Last()`
- LINQ allocates iterators and delegates - avoid in frequently called code

### 7. Unit Test Coverage
New features and new logic in non-core packages (JEngine.UI, JEngine.Util, and any future packages) MUST include unit tests:
- Target **93%+ code coverage** for all new/modified code
- **Applies to**: All `Packages/com.jasonxudeveloper.jengine.*` packages **except** `jengine.core`
- Prefer **EditMode tests** (`Tests/Editor/`) for most logic
- Use **PlayMode tests** (`Tests/Runtime/`) when runtime behavior requires it (MonoBehaviour lifecycle, scene loading, etc.) — these must run **non-interactively** (no user input, no manual scene setup)
- Cover: constructors, public API, fluent chaining, edge cases, event handlers
- Use reflection to test private methods (e.g. `OnAttachToPanel`, hover handlers) when they contain meaningful logic
- Verify tests exercise both happy paths and error/boundary conditions

## Common Issues to Flag

- Missing or insufficient unit tests for new features
- Missing XML documentation on public APIs
- Direct `Debug.Log` (should use proper logging)
- `Task` instead of `UniTask`
Expand Down
79 changes: 79 additions & 0 deletions .github/instructions/jengine.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,84 @@ internal class MyEditorClass
}
```

## Unit Testing

### Scope
Unit tests are required for all non-core JEngine packages — i.e. any package under `Packages/com.jasonxudeveloper.jengine.*` **except** `jengine.core`. This includes JEngine.UI, JEngine.Util, and any future packages.

### Coverage Requirement
New features and new logic MUST include unit tests targeting **93%+ code coverage**:
- All public methods, properties, and constructors
- Fluent API chaining
- Edge cases and error conditions
- Event handlers and callbacks (use reflection for private handlers)

### Test Modes
- **EditMode tests** (`Tests/Editor/`): Preferred for most logic — fast, no scene required.
- **PlayMode tests** (`Tests/Runtime/`): Use when the test needs a running game loop, MonoBehaviour lifecycle, or scene loading. PlayMode tests **must run non-interactively** (no user input, no manual scene setup). Use `[UnityTest]` with `UniTask.ToCoroutine()` for async PlayMode tests.

### Test Location
Tests mirror the source structure under each package's test folders:
```
Packages/com.jasonxudeveloper.jengine.ui/Editor/Components/Button/JButton.cs
→ Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/Components/Button/JButtonTests.cs

Packages/com.jasonxudeveloper.jengine.util/Runtime/JAction.cs
→ Packages/com.jasonxudeveloper.jengine.util/Tests/Editor/JActionTests.cs

# PlayMode tests when runtime behavior requires it:
Packages/com.jasonxudeveloper.jengine.util/Runtime/SomeFeature.cs
→ Packages/com.jasonxudeveloper.jengine.util/Tests/Runtime/SomeFeatureTests.cs
```

### EditMode Test Pattern
```csharp
[TestFixture]
public class MyComponentTests
{
private MyComponent _component;

[SetUp]
public void SetUp()
{
_component = new MyComponent();
}

[Test]
public void Constructor_Default_AddsBaseClass()
{
Assert.IsTrue(_component.ClassListContains("my-component"));
}
}
```

### PlayMode Test Pattern
PlayMode tests must be fully automated — no interactive input or manual scene setup:
```csharp
[TestFixture]
public class MyRuntimeTests
{
[UnityTest]
public IEnumerator MyAsyncTest() => UniTask.ToCoroutine(async () =>
{
var go = new GameObject();
var component = go.AddComponent<MyBehaviour>();
await UniTask.DelayFrame(1);
Assert.IsTrue(component.IsInitialized);
Object.Destroy(go);
});
}
```

### Testing Private Methods via Reflection
For private event handlers and internal styling methods:
```csharp
var method = typeof(MyComponent).GetMethod("OnMouseEnter",
BindingFlags.NonPublic | BindingFlags.Instance);
method.Invoke(_component, new object[] { null });
Assert.AreEqual(expectedColor, _component.style.backgroundColor.value);
```

## Review Focus Areas

When reviewing JEngine code, check:
Expand All @@ -110,3 +188,4 @@ When reviewing JEngine code, check:
3. Resource cleanup (ScriptableObjects, events)
4. Thread safety for callback-accessed state
5. Proper namespace usage
6. Unit tests with 93%+ coverage for new features/logic
Binary file not shown.
Binary file not shown.
Binary file not shown.
148 changes: 128 additions & 20 deletions UnityProject/Assets/Obfuz/SymbolObfus/symbol-mapping.xml

Large diffs are not rendered by default.

Binary file not shown.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"FileVersion": "1.0.0",
"PackageName": "main",
"PackageVersion": "260202209",
"PackageVersion": "260208645",
"Wrappers": [
{
"BundleGUID": "427571ab4f40f72802eba023fca7a5e8",
Expand All @@ -19,6 +19,14 @@
"BundleGUID": "578aebd507ab15c1f73f9a41b5962e15",
"FileName": "578aebd507ab15c1f73f9a41b5962e15.bundle"
},
{
"BundleGUID": "64a56ed51df1cee5f53c5ac4760ce454",
"FileName": "64a56ed51df1cee5f53c5ac4760ce454.bundle"
},
{
"BundleGUID": "723671f97fbc4c6dfad84ca9c9664b26",
"FileName": "723671f97fbc4c6dfad84ca9c9664b26.bundle"
},
{
"BundleGUID": "743303a92561c811cf9e428d59f4eed5",
"FileName": "743303a92561c811cf9e428d59f4eed5.bundle"
Expand All @@ -27,18 +35,10 @@
"BundleGUID": "76c5d9ebda370e318d1d711bf29db391",
"FileName": "76c5d9ebda370e318d1d711bf29db391.bundle"
},
{
"BundleGUID": "7d008b589c7529b71f703107fc14b2a1",
"FileName": "7d008b589c7529b71f703107fc14b2a1.bundle"
},
{
"BundleGUID": "a99f206109faf44e637346323f255c84",
"FileName": "a99f206109faf44e637346323f255c84.bundle"
},
{
"BundleGUID": "aa7811a04dda58d98435ef7170ce0828",
"FileName": "aa7811a04dda58d98435ef7170ce0828.bundle"
},
{
"BundleGUID": "bd7a40533fe708ab184ec75ceac853ee",
"FileName": "bd7a40533fe708ab184ec75ceac853ee.bundle"
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
260202209
260208645
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR includes updates to YooAsset StreamingAssets package versions/catalog/bundles. These look like generated build artifacts and aren’t mentioned in the PR summary. If they aren’t required for the BootstrapText/JTabView feature, consider removing them from this PR to keep the change focused and avoid accidentally shipping a new built-in catalog/version.

Copilot uses AI. Check for mistakes.

This file was deleted.

Binary file not shown.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5faecfba

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ private VisualElement CreateDefaultInspectorGUI()
// UI Settings Group
CreateUISettingsGroup();

// Text Settings Group
CreateTextSettingsGroup();

UpdateFallbackServerVisibility();

return _root;
Expand Down Expand Up @@ -440,6 +443,53 @@ private void CreateUISettingsGroup()
_root.Add(uiGroup);
}

private void CreateTextSettingsGroup()
{
var textGroup = CreateGroup("Text Settings");

var textProperty = serializedObject.FindProperty("text");

// Iterate child properties directly — no foldout
var iterator = textProperty.Copy();
var endProperty = iterator.GetEndProperty();
iterator.NextVisible(true); // enter children
while (!SerializedProperty.EqualContents(iterator, endProperty))
{
var field = new PropertyField(iterator);
field.AddToClassList("form-control");
textGroup.Add(field);
if (!iterator.NextVisible(false))
break;
}

// Reset to Defaults button
var resetRow = CreateFormRow("");
var resetButton = new UnityEngine.UIElements.Button(() =>
{
Undo.RecordObject(_bootstrap, "Reset Bootstrap Text to Defaults");
var textProp = serializedObject.FindProperty("text");
var defaults = BootstrapText.Default;
var fields = typeof(BootstrapText).GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (var field in fields)
{
var prop = textProp.FindPropertyRelative(field.Name);
if (prop != null && prop.propertyType == SerializedPropertyType.String)
{
prop.stringValue = (string)field.GetValue(defaults);
}
}
serializedObject.ApplyModifiedProperties();
});
resetButton.text = "Reset to Defaults";
resetButton.AddToClassList("form-control");
EditorUIUtils.MakeFormWidthButton(resetButton);
EditorUIUtils.SwitchButtonColor(resetButton, EditorUIUtils.ButtonType.Warning);
resetRow.Add(resetButton);
textGroup.Add(resetRow);

_root.Add(textGroup);
}

#if UNITY_EDITOR
private void CreateDevelopmentSettingsGroup()
{
Expand Down
Loading
Loading