Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite meta-check.nix type checking logic. #37252

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ let
options = callLibs ./options.nix;
types = callLibs ./types.nix;

# type checking plain nix values
types-simple = callLibs ./types-simple.nix;
Copy link
Member

Choose a reason for hiding this comment

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

Please use camelCase for attribute names.


# constants
licenses = callLibs ./licenses.nix;
systems = callLibs ./systems;
Expand Down
11 changes: 11 additions & 0 deletions lib/tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# lib tests

Here you can find tests for the library.

* Tests for the module system are defined in `./modules.sh`.
* Tests for most other library functions are defined in `./misc.sh`.

You can build everything by running `nix build -f ./release.nix`, though calling
test suites directly is considerably faster. Consult the files listed above to
find out how to do that.

8 changes: 6 additions & 2 deletions lib/tests/misc.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
# if the resulting list is empty, all tests passed
with import ../default.nix;

runTests {
# types-simple tests
import ./types-simple.nix

# misc tests
++ (runTests {


# TRIVIAL
Expand Down Expand Up @@ -360,4 +364,4 @@ runTests {
expected = true;
};

}
})
172 changes: 172 additions & 0 deletions lib/tests/types-simple.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# tests for /lib/types-simple
let lib = import ../default.nix;
in with lib.types-simple;

let

# Generate a type checker error.
# expectedType is the type expected at that position
# val is the value that was badly typed
err = expectedType: val: {
inherit val;
should = expectedType.description;
};
# a successful type check
ok = {};

# Test the checkType function results.
# type is the type to check for
# val is the value that should be of type type
# result is the expected checkType result
test = type: val: result: {
expr = checkType type val;
expected = result;
};

testDef = type: result: {
expr = defaults type;
expected = result;
};

# TODO test the return type of checkType to be
# nested attrs (product { should = string; val = any; })

in lib.runTests {

testVoid = test void 23 (err void 23);

testAnyInt = test any 42 ok;
testAnyString = test any "foo" ok;
testAnyList = test any [ 3 "45" { dont = "do this"; } "ever" ] ok;

testUnitOk = test unit {} ok;
testUnitFoo = test unit "foo" (err unit "foo");

testBoolOk = test bool true ok;
testBoolFoo = test bool 23 (err bool 23);

testStringOk = test string "foo" ok;
testStringFoo = test string false (err string false);

testIntOk = test int 42 ok;
testIntFoo = test int {} (err int {});

testFloatOk = test float 3.14 ok;
testFloatOkStrange = test float 23. ok;
testFloatNotInt = test float 23 (err float 23);
testFloatFoo = test float [ "nope" ] (err float [ "nope" ]);

testListEmpty = test (list void) [] ok;
testListIntOk = test (list int) [ 1 2 3 ] ok;
testListPosFoo = test (list int) [ 1 "ahh" 3 true ] {
"1" = (err int "ahh");
"3" = (err int true);
};
testListOfListUnitOk = test (list (list unit)) [ [] [{}] [{} {} {}] ] ok;
testListOfListUnitFoo = test (list (list unit)) [ {} [ {} "ups" ] [[]] ] {
"0" = err (list unit) {};
"1"."1" = err unit "ups";
"2"."0" = err unit [];
};

testAttrsEmpty = test (attrs void) {} ok;
testAttrsIntOk = test (attrs int) { foo = 1; bar = 2; } ok;
testAttrsIntListFoo = test (attrs int) [] (err (attrs int) []);
testAttrsIntFoo = test (attrs int) { foo.bar = 1; baz = 2; quux = true; } {
foo = err int { bar = 1; };
quux = err int true;
};
testAttrsOfAttrsOk = test (attrs (attrs unit)) { foo.bar = {}; baz.quux = {}; } ok;
testAttrsOfAttrsEmptyOk = test (attrs (attrs unit)) {} ok;
testAttrsOfAttrsFoo = test (attrs (attrs unit)) { a = []; b.c.d.e = false; } {
a = err (attrs unit) [];
b.c = err unit { d.e = false; };
};

testListOfAttrsOk1 = test (list (attrs unit)) [] ok;
testListOfAttrsOk2 = test (list (attrs unit)) [ { a = {}; } { b = {}; } ] ok;
testListOfAttrsFoo = test (list (attrs unit))
[ 42 { a = {}; b.c.d = "x"; } { x = []; } {} ]
{
"0" = err (attrs unit) 42;
"1".b = err unit { c.d = "x"; };
"2".x = err unit [];
};

testProductOk = test (product { name = string; age = int; })
{ name = "hans"; age = 42; } ok;
testProductWrongTypes = test (product { name = string; age = int; })
{ name = true; age = 23.5; }
{
name = err string true;
age = err int 23.5;
};
testProductWrongField = test (product { foo = bool; })
{ bar = "foo"; }
(err (product { foo = bool; }) { bar = "foo"; });
testProductTooManyFields = test (product { a = int; b = int; })
{ a = 1; b = 2; c = "hello"; }
(err (product { a = int; b = int; }) { a = 1; b = 2; c = "hello"; });
testProductEmptyOk = test (product {}) {} ok;
testProductEmptyFoo = test (product {}) { name = "hans"; }
(err (product {}) { name = "hans"; });

testProductOptOk = test
(productOpt { req = { a = unit; }; opt = { b = unit; }; })
{ a = {}; b = {}; } ok;
testProductOptNoOptOk = test
(productOpt { req = { a = unit; }; opt = { b = unit; }; })
{ a = {}; } ok;
testProductOnlyOptNoReq = test
(productOpt { req = { a = unit; }; opt = { b = unit; }; })
{ b = {}; }
(err (productOpt { req = { a = unit; }; opt = { b = unit; }; }) { b = {}; }) ;
testProductOnlyOptOk = test
(productOpt { req = {}; opt = { x = unit; y = unit; }; })
{ y = {}; } ok;
testProductInProductOpt = test
(productOpt { req = {}; opt = { p = product { x = int; y = bool; }; }; })
{ p = { x = 23; }; } # missing the required p.y
{ p = (err (product { x = int; y = bool; }) { x = 23; }); };

testSumLeftOk = test (sum { left = string; right = unit; })
{ left = "errör!"; } ok;
testSumRightOk = test (sum { left = string; right = unit; })
{ right = {}; } ok;
testSumWrongField = test (sum { a = int; b = bool; })
{ c = "ups"; }
(err (sum { a = int; b = bool; }) { c = "ups"; });
testSumIsNotUnion = test (sum { a = string; b = int; })
42
(err (sum { a = string; b = int; }) 42);
testSumTooManyFields = test (sum { a = int; b = unit; })
{ a = 21; b = {}; }
(err (sum { a = int; b = unit; }) { a = 21; b = {}; });

testUnionOk1 = test (union [ int string (list unit) ]) 23 ok;
testUnionOk2 = test (union [ int string (list unit) ]) "foo" ok;
testUnionOk3 = test (union [ int string (list unit) ]) [{}{}] ok;
testUnionWrongType = test (union [ int string ]) true
(err (union [ int string ]) true);
testUnionOne = test (union [ int ]) 23 ok;


testDefaultsUnit = testDef unit {};
testDefaultsBool = testDef bool false;
testDefaultsString = testDef string "";
testDefaultsInt = testDef int 0;
testDefaultsFloat = testDef float 0.0;
testDefaultsList1 = testDef (list void) [];
testDefaultsList2 = testDef (list (list void)) [];
testDefaultsAttrs1 = testDef (attrs void) {};
testDefaultsAttrs2 = testDef (attrs (attrs void)) {};
testDefaultsProductEmpty = testDef (product {}) {};
testDefaultsProduct = testDef
(product { a = int; b = bool; })
{ a = 0; b = false; };
testDefaultsSum = testDef
(sum { a = int; b = bool; })
{ a = 0; }; # depends on sorting of attrNames
testDefaultsUnion = testDef (union [ int bool ]) 0;

}