Files
cappuccino/Tests/AppKit/DropInBaselineTest.j
T
David Richardson 17198938e0 Tests: Add regression test suites for table drawing and drop-in compatibility
Adds targeted test infrastructure and validation checks to protect table drawing hooks and drop-in framework contracts against unintended modifications.

* CPTableViewDrawingTest: Verifies subclass invocation order for drawing steps and ensures application-specified background colors persist across theme-state changes.

* DropInCompatibilityTest: Validates default theme names, window control configurations, pop-up button bezel styles, and table class defaults.

* DropInSnapshot: Encapsulates theme attribute defaults, public API surface, default view construction, and window controls as structured data.

* DropInBaselineGenerator: Provides tooling to capture current framework state as a baseline.

* DropInBaselineTest: Compares framework artifacts against the established baseline, permitting additions while reporting modifications and removals.

* DropInBaseline.json: Introduces the initial compatibility baseline artifact.
2026-10-31 15:58:31 -06:00

181 lines
5.2 KiB
Plaintext

/*
* DropInBaselineTest.j
* AppKit
*
* Created by David Richardson on 31/10/2026.
* Copyright David Richardson 2026.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "DropInSnapshot.j"
/*
Compares the running frameworks with the recorded drop-in baseline. See
DropInSnapshot.j for what the baseline holds and DropInBaselineGenerator.j for
how to update it.
Each test reports every difference it finds. A list is more useful here than
a failure at the first difference, because one change often affects several
classes.
*/
var fs = require("fs"),
path = require("path"),
DropInBaseline = nil,
DropInCurrent = nil;
@implementation DropInBaselineTest : OJTestCase
- (void)setUp
{
// This will init the global var CPApp which are used internally in the AppKit
[[CPApplication alloc] init];
if (DropInBaseline)
return;
var baselinePath = path.join(path.dirname(__filename), "Resources", "DropInBaseline.json");
DropInBaseline = JSON.parse(fs.readFileSync(baselinePath, {encoding: 'utf-8'}));
DropInCurrent = DropInCreateSnapshot();
}
- (void)assertNoDifferences:(CPArray)differences
{
[self assertTrue:differences.length === 0 message:"\n" + differences.join("\n")];
}
/*
A themed application reads these values whenever its theme supplies none, so a
changed default changes the application.
*/
- (void)testThemeAttributeDefaultsAreUnchanged
{
var differences = [];
for (var className in DropInBaseline.themeAttributes)
{
var expected = DropInBaseline.themeAttributes[className],
current = DropInCurrent.themeAttributes[className];
if (!current)
{
differences.push(className + ": class no longer declares theme attributes");
continue;
}
for (var attribute in expected)
if (expected[attribute] !== current[attribute])
differences.push(className + " " + attribute + ": " + expected[attribute] + " is now " + current[attribute]);
}
[self assertNoDifferences:differences];
}
- (void)testPublicClassesExist
{
var differences = DropInBaseline.publicClasses.filter(function(aName)
{
return !objj_getClass(aName);
});
[self assertNoDifferences:differences];
}
/*
A public method may move to a superclass, since the class still responds to it.
It may not disappear. This test cannot detect a method that remains but no
longer does its work. Behavior tests cover that.
*/
- (void)testPublicMethodsExist
{
var differences = [];
DropInBaseline.publicClasses.forEach(function(aName)
{
var aClass = objj_getClass(aName);
if (!aClass)
return;
DropInBaseline.instanceMethods[aName].forEach(function(aSelector)
{
if (!class_getInstanceMethod(aClass, aSelector))
differences.push("-[" + aName + " " + aSelector + "]");
});
DropInBaseline.classMethods[aName].forEach(function(aSelector)
{
if (!class_getClassMethod(aClass, aSelector))
differences.push("+[" + aName + " " + aSelector + "]");
});
});
[self assertNoDifferences:differences];
}
/*
A view created in code has these values until the application changes them.
*/
- (void)testDefaultViewConstructionIsUnchanged
{
var differences = [];
for (var className in DropInBaseline.construction)
{
var expected = DropInBaseline.construction[className],
current = DropInCurrent.construction[className];
if (!current)
{
differences.push(className + ": cannot be created");
continue;
}
for (var key in expected)
{
var expectedValue = String(expected[key]),
currentValue = String(current[key]);
if (expectedValue !== currentValue)
differences.push(className + " " + key + ": " + expectedValue + " is now " + currentValue);
}
}
[self assertNoDifferences:differences];
}
/*
The public subviews of a window view are the controls a person sees in the
title bar, so they are part of how an existing application looks.
*/
- (void)testWindowControlsAreUnchanged
{
var differences = [];
for (var style in DropInBaseline.windows)
{
var expected = String(DropInBaseline.windows[style]),
current = String(DropInCurrent.windows[style]);
if (expected !== current)
differences.push(style + ": " + expected + " is now " + current);
}
[self assertNoDifferences:differences];
}
@end